50.服务程序SERVICE_STATUS、SERVICE_STATUS_HANDLE、RegisterServiceCtrlHandler、SetServiceStatus、SERVICE_TABL

我得先总结一下步骤:

一、在main函数中的操作
1.先创建一个main主函数,在main主函数中创建创建一个服务程序入口函数列的结构体并将其初始化
机构体SERVICE_TABLE_ENTRY DispatchTable[2];
假设定义的服务入口函数是(LPSERVICE_MAIN_FUNCTION)ServiceMain0
2.由服务程序入口函数表启动一个新服务程序线程
SERVICE_TABLE_ENTRY DispatchTable[2]

二、在(LPSERVICE_MAIN_FUNCTION)ServiceMain0函数中的操作
3.在服务程序入口主函数中,创建一个服务状态的结构体,并将其初始化SERVICE_STATUS
SERVICE_STATUS m_ServiceStatus;
4.注册服务状态控制函数
SERVICE_STATUS_HANDLE m_ServiceStatusHandle = RegisterServiceCtrlHandler(“zcm_service0”,(LPHANDLER_FUNCTION)ServiceCtrlHandler0);
注册服务状态控制函数后,会返回一个操作状态服务函数的句柄,注册成功之后,其实服务就已经开始运行了
5.修改服务程序的工作状态,并将修改后的状态报告SCM管理程序
//修改服务状态
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
//报告运行状态到mc
SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);
6.状态报告给SCM管理程序后,我们的服务就可以正常进行了,用一个while(bRunning)循环,不断处理各种情况,提供服务

三、服务状态管理程序(LPHANDLER_FUNCTION)ServiceCtrlHandler0) 函数中的操作
对服务程序的启动、停止、暂停、恢复功能进行操作
根据传递的参数,用switch(dwControl )对各种状态情况进行处理
1.当收到不同的状态时,将采取一定的操作,控制第二步(LPSERVICE_MAIN_FUNCTION)ServiceMain0函数中的操作
switch(Opcode)
{
case SERVICE_CONTROL_STOP:
bRunning = FALSE;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
case SERVICE_CONTROL_SHUTDOWN:
bRunning = FALSE;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
break;
default:
break;
}
2.ServiceMain0函数响应状态后,并执行了相关的操作,那么,再次报告工作状态给scm管理程序

对服务管理程序中的三个函数的分工和之前的联系进行说明,这也正是软件设计步骤,后面就是详细的参数和函数的具体使用

服务程序编好之后,不能双击执行,有三种方法进行操作
1.使用Services.msc程序进行可视化的编辑,操纵服务工作状态,缺点是不能添加我们写的程序到服务列表中
2.使用mc.exe程序进行控制zcm为我创建的服务名
mc.exe create zcm binpath= c:\zcm_service.exe //创建服务
mc.exe query zcm //查询服务状态
mc.exe start zcm //启动服务
mc.exe stop zcm //停止服务
mc.exe delete zcm //卸载服务
编译好的服务程序zcm_service.exe
命令方式操作服务程序
3.编写代码来控制SCM,自动化的处理方法,推荐

1.SERVICE_STATUS 是服务状态结构,用于标记服务的状态

typedef struct _SERVICE_STATUS {DWORD   dwServiceType; //服务可执行文件的类型DWORD   dwCurrentState;DWORD   dwControlsAccepted;DWORD   dwWin32ExitCode;DWORD   dwServiceSpecificExitCode;DWORD   dwCheckPoint;DWORD   dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;

dwServiceType 的取值说明:

// Service Types (Bit Mask)
#define SERVICE_WIN32_OWN_PROCESS      0x00000010 //可执行文件中只有一个单独的服务
#define SERVICE_WIN32_SHARE_PROCESS    0x00000020 //拥有多个服务
#define SERVICE_WIN32                  (SERVICE_WIN32_OWN_PROCESS | \SERVICE_WIN32_SHARE_PROCESS) // win32程序服务
#define SERVICE_INTERACTIVE_PROCESS    0x00000100  //服务需要和桌面发生交互#define SERVICE_KERNEL_DRIVER          0x00000001 //核心服务
#define SERVICE_FILE_SYSTEM_DRIVER     0x00000002 //文件系统服务
#define SERVICE_ADAPTER                0x00000004 //适配器服务
#define SERVICE_RECOGNIZER_DRIVER      0x00000008#define SERVICE_DRIVER                 (SERVICE_KERNEL_DRIVER | \SERVICE_FILE_SYSTEM_DRIVER | \SERVICE_RECOGNIZER_DRIVER)#define SERVICE_INTERACTIVE_PROCESS    0x00000100#define SERVICE_TYPE_ALL               (SERVICE_WIN32  | \SERVICE_ADAPTER | \SERVICE_DRIVER  | \SERVICE_INTERACTIVE_PROCESS)

dwCurrentState 用于通知SCManger

// Service State -- for CurrentState
//
#define SERVICE_STOPPED                        0x00000001 //服务停止
#define SERVICE_START_PENDING                  0x00000002 //初始态,用于初始化,将要开始运行服务
#define SERVICE_STOP_PENDING                   0x00000003 //将要停止服务
#define SERVICE_RUNNING                        0x00000004 //服务正在运行
#define SERVICE_CONTINUE_PENDING               0x00000005 //将要暂停后继续
#define SERVICE_PAUSE_PENDING                  0x00000006 //将要暂停
#define SERVICE_PAUSED                         0x00000007 //服务已暂停

dwControlsAccepted 服务接受什么样的控制通知

// Controls Accepted  (Bit Mask)
//
#define SERVICE_ACCEPT_STOP                    0x00000001 //该服务可以被停止
#define SERVICE_ACCEPT_PAUSE_CONTINUE          0x00000002 //该服务可以被暂停和继续
#define SERVICE_ACCEPT_SHUTDOWN                0x00000004 //当系统关闭时通知该服务
#define SERVICE_ACCEPT_PARAMCHANGE             0x00000008 //该服务可以在不停止和重启的情况下重新读取其启动参数
#define SERVICE_ACCEPT_NETBINDCHANGE           0x00000010 //该服务是一个网络成分,可在不停止和重启的情况下接受绑定的变化
#define SERVICE_ACCEPT_HARDWAREPROFILECHANGE   0x00000020
#define SERVICE_ACCEPT_POWEREVENT              0x00000040
#define SERVICE_ACCEPT_SESSIONCHANGE           0x00000080
#define SERVICE_ACCEPT_PRESHUTDOWN             0x00000100 //该服务可执行预关闭任务
#define SERVICE_ACCEPT_TIMECHANGE              0x00000200
#define SERVICE_ACCEPT_TRIGGEREVENT            0x00000400

dwWin32ExitCode:错误码,用于在服务启动或关闭时报错;默认设置为0
dwServiceSpecificExitCode:特定于服务的错误码,用于在服务启动或关闭时报错;默认设置为0
dwCheckPoint:检测点值,服务周期性的增加该值,以报告服务在一段长期时间内所做的启动,停止,暂停,继续的处理;默认设置为0
dwWaitHint:以毫秒为单位的估计时间,用于估计启动、停止、暂停、继续操作的时间;默认设置为0,只有当服务启动超过三十秒时,才进行设置

SERVICE_STATUS_HANDLE 服务状态句柄
RegisterServiceCtrlHandler注册服务状态控制函数,将LPHANDLER_FUNCTION的服务状态函数注册到zcm_service0的服务中去,然后返回一个可操作的服务状态句柄

SERVICE_STATUS_HANDLE m_ServiceStatusHandle = RegisterServiceCtrlHandler("zcm_service0",(LPHANDLER_FUNCTION)ServiceCtrlHandler0);

注册成功服务状态函数后,就可以修改服务的状态信息,将服务由初始化的SERVICE_START_PENDING修改为SERVICE_RUNNING状态

//修改服务状态
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
//报告运行状态到mc
SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);

SERVIcE_STATUS结构体的状态修改后,要将修改后的状态信息设置到scManger管理程序中
RegisterServiceCtrlHandler 注册服务函数

__checkReturn
WINADVAPI
SERVICE_STATUS_HANDLE
WINAPI
RegisterServiceCtrlHandlerA(__in    LPCSTR                    lpServiceName, //服务名称__in    __callbackLPHANDLER_FUNCTION          lpHandlerProc //服务状态控制函数);
__checkReturn
WINADVAPI
SERVICE_STATUS_HANDLE
WINAPI
RegisterServiceCtrlHandlerW(__in    LPCWSTR                    lpServiceName,__in    __callbackLPHANDLER_FUNCTION          lpHandlerProc);
#ifdef UNICODE
#define RegisterServiceCtrlHandler  RegisterServiceCtrlHandlerW
#else
#define RegisterServiceCtrlHandler  RegisterServiceCtrlHandlerA
#endif // !UNICODE

SetServiceStatus 服务状态设置函数,修改服务状态后,要将服务状态设置到scm管理器中

WINADVAPI
BOOL
WINAPI
SetServiceStatus(__in        SERVICE_STATUS_HANDLE   hServiceStatus, //服务状态操作句柄__in        LPSERVICE_STATUS        lpServiceStatus //SERVICE_STATUS状态结构体指针);

LPHANDLER_FUNCTION服务状态控制函数,还有一个Ex的版本

//
// Prototype for the Service Control Handler Function
//typedef VOID (WINAPI *LPHANDLER_FUNCTION)(DWORD    dwControl //状态参数);typedef DWORD (WINAPI *LPHANDLER_FUNCTION_EX)(DWORD    dwControl, //状态参数DWORD    dwEventType,LPVOID   lpEventData,LPVOID   lpContext);

dwControl状态控制

/ Controls
//
#define SERVICE_CONTROL_STOP                   0x00000001 //停止
#define SERVICE_CONTROL_PAUSE                  0x00000002 //暂停
#define SERVICE_CONTROL_CONTINUE               0x00000003 //继续
#define SERVICE_CONTROL_INTERROGATE            0x00000004 //查询
#define SERVICE_CONTROL_SHUTDOWN               0x00000005 //关机时
#define SERVICE_CONTROL_PARAMCHANGE            0x00000006 //参数变化进
#define SERVICE_CONTROL_NETBINDADD             0x00000007 //网络绑定时
#define SERVICE_CONTROL_NETBINDREMOVE          0x00000008
#define SERVICE_CONTROL_NETBINDENABLE          0x00000009
#define SERVICE_CONTROL_NETBINDDISABLE         0x0000000A
#define SERVICE_CONTROL_DEVICEEVENT            0x0000000B
#define SERVICE_CONTROL_HARDWAREPROFILECHANGE  0x0000000C
#define SERVICE_CONTROL_POWEREVENT             0x0000000D
#define SERVICE_CONTROL_SESSIONCHANGE          0x0000000E
#define SERVICE_CONTROL_PRESHUTDOWN            0x0000000F
#define SERVICE_CONTROL_TIMECHANGE             0x00000010 
#define SERVICE_CONTROL_TRIGGEREVENT           0x00000020

Service服务入口表,如果是一个程序入口程,则将结构体设置成2个成员的数组,如果是2个入口函数,则设置成员为3,最后一个成员的服务名和入口函数都要设置为NULL

// Service Start Table
//typedef struct _SERVICE_TABLE_ENTRYA {LPSTR                       lpServiceName; //服务名LPSERVICE_MAIN_FUNCTIONA    lpServiceProc; //服务程序入口函数
}SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
typedef struct _SERVICE_TABLE_ENTRYW {LPWSTR                      lpServiceName;LPSERVICE_MAIN_FUNCTIONW    lpServiceProc;
}SERVICE_TABLE_ENTRYW, *LPSERVICE_TABLE_ENTRYW;
#ifdef UNICODE
typedef SERVICE_TABLE_ENTRYW SERVICE_TABLE_ENTRY;
typedef LPSERVICE_TABLE_ENTRYW LPSERVICE_TABLE_ENTRY;
#else
typedef SERVICE_TABLE_ENTRYA SERVICE_TABLE_ENTRY;
typedef LPSERVICE_TABLE_ENTRYA LPSERVICE_TABLE_ENTRY;
#endif // UNICODE

在main主函数中启动一个线程,用于创建一个新的线程
//定义并初始化一个服务入口函数表
SERVICE_TABLE_ENTRY DispatchTable[2];
DispatchTable[0].lpServiceName = “zcm_service0”;
DispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain0;
DispatchTable[1].lpServiceName = NULL;//“zcm_service1”;
DispatchTable[1].lpServiceProc = NULL;//(LPSERVICE_MAIN_FUNCTION)ServiceMain1;
//根据服务入口函数表,创建一个新的线程
StartServiceCtrlDispatcher(DispatchTable);

下而是实例程序

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define SLEEP_TIME 5000
#define LOG_FILE_NAME "C:\\Documents and Settings\\Administrator\\My Documents\\visual studio 2010\\Projects\\zcm_service\\Debug\\debug.log"BOOL bRunning = TRUE;//是否运行,控制主函数
SERVICE_STATUS m_ServiceStatus; //服务状态结构
SERVICE_STATUS_HANDLE m_ServiceStatusHandle; //服务状态句柄void WINAPI ServiceMain0(int argc,char* argv[]);
//void WINAPI ServiceMain1(int argc,char* argv[]);void ServiceCtrlHandler0(DWORD Opcode);
//void ServiceCtrlHandler1(DWORD Opcode);void WriteToLog(LPTSTR szStr);int main(int argc,char* argv[])
{//创建服务程序入口函数表SERVICE_TABLE_ENTRY DispatchTable[2];DispatchTable[0].lpServiceName = "zcm_service0";DispatchTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain0;DispatchTable[1].lpServiceName = NULL;//"zcm_service1";DispatchTable[1].lpServiceProc = NULL;//(LPSERVICE_MAIN_FUNCTION)ServiceMain1;//DispatchTable[2].lpServiceName = NULL;//DispatchTable[2].lpServiceProc = NULL;//创建一个新的线程StartServiceCtrlDispatcher(DispatchTable);return 0;
}//服务入口主函数
void WINAPI ServiceMain0(int argc,char* argv[])
{MEMORYSTATUS memstatus;TCHAR szBuffer[256];int avaible_MB = 0;memset(szBuffer,0,256);//初始化服务状态m_ServiceStatus.dwServiceType = SERVICE_WIN32;m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE;m_ServiceStatus.dwWin32ExitCode = 0;m_ServiceStatus.dwServiceSpecificExitCode = 0;m_ServiceStatus.dwCheckPoint = 0;m_ServiceStatus.dwWaitHint = 0;//注册服务状态控制函数m_ServiceStatusHandle = RegisterServiceCtrlHandler("zcm_service0",(LPHANDLER_FUNCTION)ServiceCtrlHandler0);if(m_ServiceStatusHandle == 0){WriteToLog("RegisterServiceCtrlHandler ERROR!");return;}else{WriteToLog("RegisterServiceCtrlHandler OK!");}//修改服务状态m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;//报告运行状态到mcSetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);bRunning = TRUE;while(bRunning){//服务程序的主体GlobalMemoryStatus(&memstatus);avaible_MB = memstatus.dwAvailPhys / 1024 /1024;wsprintf(szBuffer,"Memory:%d",avaible_MB);WriteToLog(szBuffer);Sleep(SLEEP_TIME);}//bRunning = FALSEm_ServiceStatus.dwCurrentState = SERVICE_STOP;SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);WriteToLog("Program is Stoped!");return;
}//服务控制函数
//启动、停止、暂停、恢复操作,对这些功能进行操作
void ServiceCtrlHandler0(DWORD Opcode)
{switch(Opcode){case SERVICE_CONTROL_STOP:bRunning = FALSE;m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;break;case SERVICE_CONTROL_SHUTDOWN:bRunning = FALSE;m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;break;default:break;}SetServiceStatus(m_ServiceStatusHandle,&m_ServiceStatus);
}void WriteToLog(LPSTR szStr)
{FILE* fp;fopen_s(&fp,LOG_FILE_NAME,"a+");if(!fp){return ;}fprintf(fp,"%s\n",szStr);fclose(fp);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/1618488.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

使用 SAP WebIDE 将 SAP UI5 应用部署到 ABAP 系统时遇到的关于传输请求的错误

有朋友遇到一个在 webide 里部署 SAP UI5 应用到 ABAP Repository 里时出错的问题&#xff1a; 错误消息&#xff1a; Failed to get transports for the selected package. Request POST /webidedispatcher/destinations/LND500/sap/bc/adt/cts/transportchecks failed: Forbi…

【操作记录】CLion 中引入 Gurobi 并使用 C++ 编程

文章目录 一、前言二、具体操作2.1 创建项目2.2 修改编译工具2.3 修改 CMakeLists.txt2.4 修改 main.cpp2.5 运行测试 一、前言 虽然C编程大部分人都会选择使用VS&#xff0c;但是作为 IDEA 的长期用户&#xff0c;我还是比较习惯 JetBrains 风格的编译器&#xff0c;所以就选…

7.11英语学习及笔记

《花木兰》 Based on a Chinese legend, the film follows the story of the titular hero – a young woman who poses as a man in order to take her ailing father’s place in the Imperial army, after the threat of the invading Huns requires a man from every house…

针对韩国开展的一系列韩文类恶意文档定向攻击行动分析 part-1

?点个关注&#xff0c;你的支持是我更新最大的动力? 最近朝鲜APT组织的攻击事件层出不穷&#xff0c;基于看到一篇很好的文章&#xff0c;特此结合文章对朝鲜相关组织进行分析。 Financial Security Institute对近期一系列投放韩文类恶意文档的定向攻击行动命名为“DOKKAEBI…

跨国邮件诈骗团伙案例

如果某天你收到了这样一封邮件&#xff0c;啊&#xff0c;大体意思就是这人身患绝症且有一笔遗产&#xff0c;你是个幸运儿要你继承。 重点来了啊&#xff0c;他会伪造证件然后让你相信并按照对方的思路来&#xff0c;给他你的身份信息&#xff0c;例如身份证照片&#xff0c;你…

springboot+vue+Elementui图书馆自习室座位预约系统

随着学校的人数的扩招,图书馆的座位资源短缺问题日益严重&#xff0c;特别是在临近考试时&#xff0c;座位占座情况尤为明显。起大早、摞书本、放水杯&#xff0c;甚至粘上纸条……宣誓主权&#xff0c;在图书馆里&#xff0c;很多学生办法用尽&#xff0c;只为了能获得“一席之…

SQLite3 极简教程 Go 使用 SQLite 内存模式操作数据结构

SQLite 简介 关键词: RDBMS (embedded), C SQLite is a database engine written in the C language. It is not a standalone app; rather, it is a library that software developers embed in their apps. SQLite是一个开源的、内嵌式的关系型数据库。它最初发布于2000年,…

致--所有努力生活的人们(暑假学习总结与考研宣誓)

致--所有努力生活的人们 确定专业和院校科研任务关于英语的学习退游喜欢的女孩备战数模比赛学习智能算法计算机素养的锻炼basketball对未来的展望 虽然文章写的虽然不是很好&#xff0c;但是很用心有诚意&#xff0c;我保证读完你会充满慢慢能量的&#xff01; 本blog记录了暑假…

有书共读:《穷查理宝典》

1. 写在前面 最近有幸参加了Datawhale举办的一些读书会活动&#xff0c;里面有很多伙伴分享自己读过的一些好书并分享自己的读书心得和感悟&#xff0c;体会非常的深刻&#xff0c; 也学习到了很多的知识&#xff0c; 所以受到了一些伙伴的影响&#xff0c;最近也开始在闲暇的…

以“人民的名义”劝你快去读点书

“我之前看一个调查&#xff0c;说中国人的读书量远低于世界平均水平&#xff1b;而且趋于图片化、碎片化&#xff0c;缺乏深度。这年头&#xff0c;你们还有个读书会&#xff0c;算是难得了”&#xff0c;陆亦可对赵东来说。“而且我们读的还是闲书&#xff0c;没有任何经济利…

第三讲,三维空间刚体运动

一个刚体在三维空间中的运动是如何描述的。我们当然知道这由一次旋转加一次平移组成。平移确实没有太大问题&#xff0c;但旋转的处理是件麻烦事。我们将介绍旋转矩阵、四 元数、欧拉角的意义&#xff0c;以及它们是如何运算和转换的。 1.向量&#xff0c;坐标系和旋转矩阵 点…

两独立样本的非参数检验(Mann-Whitney U 秩和检验)

原文地址&#xff1a;SPSS学习笔记之——两独立样本的非参数检验&#xff08;Mann-Whitney U 秩和检验&#xff09;作者&#xff1a;王江源 一、概述 Mann-Whitney U 检验是用得最广泛的两独立样本秩和检验方法。简单的说&#xff0c;该检验是与独立样本t检验相对应的方法&…

不止基因编辑 当所有技术都可能成为毒药

基因技术、纳米技术、机器人技术的新潘多拉之盒即将开启&#xff0c;你我却毫无查觉。我们不单受到大规模杀伤性武器的威胁&#xff0c;还有技术知识产生的大规模杀伤力。这一邪恶的力量&#xff0c;正由国家力量支持的大规模杀伤性武器&#xff0c;转向极端的个人。——Bill J…

市场的霸主:对冲基金世界的超额回报大师

《市场的霸主&#xff1a;对冲基金世界的超额回报大师》 基本信息 作者&#xff1a; (美)马妮特.阿胡贾(Maneet Ahuja) 译者&#xff1a; 毕崇毅 郑磊 出版社&#xff1a;机械工业出版社 ISBN&#xff1a;9787111425441 上架时间&#xff1a;2013-5-29 出版日期&#xff1a;201…

革命性新疗法后 第三例艾滋病治愈病例可能出现了!

伦敦病人的例子说明&#xff0c;柏林病人被治愈并非出于侥幸&#xff0c;而是可以被复制的。 艾滋病患者通常要终身每日服用病毒抑制药物。一旦停药&#xff0c;病毒就会在两三周内卷土重来。 新浪科技讯 北京时间3月12日消息&#xff0c;据国外媒体报道&#xff0c;一名德国艾…

SPSS学习笔记(三)方差分析ANOVA(F检验)

目录 一、单因素ANOVA 分析 过程 结果及分析 二、双因素ANOVA 案例及分析 过程 结果及分析 一、单因素ANOVA 单因素方差分析是两个样本平均数比较的引伸&#xff0c;它是用来检验多个平均数之间的差异&#xff0c;从而确定一种因素对试验结果有无显著性影响的统计方法…

JavaSE学习——异常

目录 一、异常概述 二、异常的体系结果 二、异常的处理&#xff1a;抓抛模型 三、try-catch-finally的使用 四、throws 异常类型 的使用 五、开发中如何选择使用try-catch-finally还是使用throws&#xff1f; 六、自定义异常 自定义异常步骤&#xff1a; 七、总结&a…

CAN总线学习——物理层、数据链路层、CANopen协议

1、CAN总线介绍 1.1、CAN总线描述 (1)CAN总线支持多节点通信&#xff0c;但是节点不分区主从&#xff0c;也就是不存在一个节点来负责维护总线的通信&#xff1b;这点可以和I2C总线对对比&#xff0c;I2C是一主多从模式&#xff1b; (2)是差分、异步、串行总线&#xff0c;采用…

MybatisPlus拦截器实战之数据的加解密和脱敏

文章目录 一、前言二、拦截器简介三、代码目录结构简介四、核心代码讲解4.1 application.yml文件4.2 自定义注解4.2.1 SensitiveEntity4.2.2 SensitiveData4.2.3 MaskedEntity4.2.4 MaskedField4.2.5 MaskedMethod 4.3 Mybatis-Plus 拦截器数据自动加密4.4 Mybatis 打印完整sql…

ChromeOS 的 Linux 操作系统和 Chrome 浏览器分离

导读科技媒体 Ars Technica 报道称&#xff0c;谷歌正在将 ChromeOS 的浏览器从操作系统中分离出来 —— 让它变得更像 Linux。虽然目前还没有任何官方消息&#xff0c;但这项变化可能会在本月的版本更新中推出。 据介绍&#xff0c;谷歌将该项目命名为 "Lacros"——…