DelphiMVCFrameWork 源码分析(一)

news2024/11/15 8:32:18

Delphi 基础Web Service Application 见:

Delphi Web Server 流程分析_看那山瞧那水的博客-CSDN博客

 DataSnap的见:

Delphi DataSnap 流程分析(一)_看那山瞧那水的博客-CSDN博客

Delphi DataSnap 流程分析(二)_看那山瞧那水的博客-CSDN博客

 DelphiMVCFrameWork 是个开源的框架,Star 已经1.1K+了,在Pascal里算比较高了。

https://github.com/danieleteti/delphimvcframework

DelphiMVCFrameWork框架的网络通信也是基于Delphi WebBroker技术(早期版本是基于IOComp),使用REST架构。正如框架名称,采用服务端的MVC架构,具体是采用了路由器(Router),控制器(Controler),中间件(Middleware)等结构,这样松耦合的结构,更有利于项目的开发和构建,也更有利用项目的扩展和维护。同时,也可以采用同个作者开源的ORM框架,MVCActivedWork,这样可以更简便开发Database运用。

DelphiMVCFrameWork框架如何挂钩Delphi的WebService?

“Delphi Web Server 流程分析”里,当调用TCustomWebDispatcher.DispatchAction(),

提到:

" Result := DoBeforeDispatch(Request, Response) or Response.Sent;
注意这一行代码!!!这里可以让我们有机会插入请求处理过程及结果。嗯,我们可以在这里"截胡"。"


function TCustomWebDispatcher.DoBeforeDispatch(Request: TWebRequest; Response: TWebResponse): Boolean;
begin
  Result := False;
  if Assigned(FBeforeDispatch) then
    FBeforeDispatch(Self, Request, Response, Result);
end;

 DoBeforeDispatch()方法就是执行TWebModule的OnBeforeDispatch事件。

 DelphiMVCFrameWork框架就是通过OnBeforeDispatch事件开始"截胡"。这是通过框架的基础核心类TMVCEngine来实现的:

constructor TMVCEngine.Create(const AWebModule: TWebModule; const AConfigAction: TProc<TMVCConfig>;
  const ACustomLogger: ILogWriter);
begin
  inherited Create(AWebModule);
  FWebModule := AWebModule;
  FixUpWebModule;
  FConfig := TMVCConfig.Create;
  FSerializers := TDictionary<string, IMVCSerializer>.Create;
  FMiddlewares := TList<IMVCMiddleware>.Create;
  FControllers := TObjectList<TMVCControllerDelegate>.Create(True);
  FApplicationSession := nil;
  FSavedOnBeforeDispatch := nil;

  WebRequestHandler.CacheConnections := True;
  WebRequestHandler.MaxConnections := 4096;

  MVCFramework.Logger.SetDefaultLogger(ACustomLogger);
  ConfigDefaultValues;

  if Assigned(AConfigAction) then
  begin
    LogEnterMethod('Custom configuration method');
    AConfigAction(FConfig);
    LogExitMethod('Custom configuration method');
  end;
  FConfig.Freeze;
  SaveCacheConfigValues;
  RegisterDefaultsSerializers;
  LoadSystemControllers;
end;

procedure TMVCEngine.FixUpWebModule;
begin
  FSavedOnBeforeDispatch := FWebModule.BeforeDispatch;
  FWebModule.BeforeDispatch := OnBeforeDispatch;
end;

TMVCEngine创建的时候传入TWebModule实例,然后挂钩OnBeforeDispatch事件,FSavedOnBeforeDispatch 先保存已有的事件,先处理TMVCEngine,处理完后再恢复执行(如果有)。


procedure TMVCEngine.OnBeforeDispatch(ASender: TObject; ARequest: TWebRequest;
  AResponse: TWebResponse; var AHandled: Boolean);
begin
  AHandled := False;
  { there is a bug in WebBroker Linux on 10.2.1 tokyo }
  // if Assigned(FSavedOnBeforeDispatch) then
  // begin
  // FSavedOnBeforeDispatch(ASender, ARequest, AResponse, AHandled);
  // end;

  if IsShuttingDown then
  begin
    AResponse.StatusCode := http_status.ServiceUnavailable;
    AResponse.ContentType := TMVCMediaType.TEXT_PLAIN;
    AResponse.Content := 'Server is shutting down';
    AHandled := True;
  end;

  if not AHandled then
  begin
    try
      AHandled := ExecuteAction(ASender, ARequest, AResponse);
      if not AHandled then
      begin
        AResponse.ContentStream := nil;
      end;
    except
      on E: Exception do
      begin
        Log.ErrorFmt('[%s] %s', [E.Classname, E.Message], LOGGERPRO_TAG);

        AResponse.StatusCode := http_status.InternalServerError; // default is Internal Server Error
        if E is EMVCException then
        begin
          AResponse.StatusCode := (E as EMVCException).HTTPErrorCode;
        end;

        AResponse.Content := E.Message;
        AResponse.SendResponse;
        AHandled := True;
      end;
    end;
  end;
end;

IsShuttingDown使用同步锁实现判断Server是否下线:


function IsShuttingDown: Boolean;
begin
  Result := TInterlocked.Read(gIsShuttingDown) = 1
end;

先插入2张图,说明Router、Controler、Middleware的动作系列:

                                  MVCEngine,Router,Controler系列图

                        MVCEngine,Router,Controler,MiddleWare系列图


回头看代码,TMVCEngine.ExecuteAction():


function TMVCEngine.ExecuteAction(const ASender: TObject; const ARequest: TWebRequest;
  const AResponse: TWebResponse): Boolean;
var
  lParamsTable: TMVCRequestParamsTable;
  lContext: TWebContext;
  lRouter: TMVCRouter;
  lHandled: Boolean;
  lResponseContentMediaType: string;
  lResponseContentCharset: string;
  lRouterMethodToCallName: string;
  lRouterControllerClazzQualifiedClassName: string;
  lSelectedController: TMVCController;
  lActionFormalParams: TArray<TRttiParameter>;
  lActualParams: TArray<TValue>;
  lBodyParameter: TObject;
begin
  Result := False;

  if ARequest.ContentLength > FConfigCache_MaxRequestSize then
  begin
    raise EMVCException.CreateFmt(http_status.RequestEntityTooLarge,
      'Request size exceeded the max allowed size [%d KiB] (1)',
      [(FConfigCache_MaxRequestSize div 1024)]);
  end;

{$IF Defined(BERLINORBETTER)}
  ARequest.ReadTotalContent;

  // Double check for malicious content-length header
  if ARequest.ContentLength > FConfigCache_MaxRequestSize then
  begin
    raise EMVCException.CreateFmt(http_status.RequestEntityTooLarge,
      'Request size exceeded the max allowed size [%d KiB] (2)',
      [(FConfigCache_MaxRequestSize div 1024)]);
  end;
{$ENDIF}
  lParamsTable := TMVCRequestParamsTable.Create;
  try
    lContext := TWebContext.Create(ARequest, AResponse, FConfig, FSerializers);
    try
      DefineDefaultResponseHeaders(lContext);
      DoWebContextCreateEvent(lContext);
      lHandled := False;
      lRouter := TMVCRouter.Create(FConfig, gMVCGlobalActionParamsCache);
      try // finally
        lSelectedController := nil;
        try // only for lSelectedController
          try // global exception handler
            ExecuteBeforeRoutingMiddleware(lContext, lHandled);
            if not lHandled then
            begin
              if lRouter.ExecuteRouting(ARequest.PathInfo,
                lContext.Request.GetOverwrittenHTTPMethod { lContext.Request.HTTPMethod } ,
                ARequest.ContentType, ARequest.Accept, FControllers,
                FConfigCache_DefaultContentType, FConfigCache_DefaultContentCharset,
                FConfigCache_PathPrefix, lParamsTable, lResponseContentMediaType,
                lResponseContentCharset) then
              begin
                try
                  if Assigned(lRouter.ControllerCreateAction) then
                    lSelectedController := lRouter.ControllerCreateAction()
                  else
                    lSelectedController := lRouter.ControllerClazz.Create;
                except
                  on Ex: Exception do
                  begin
                    Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                      [Ex.Classname, Ex.Message, GetRequestShortDescription(ARequest), 'Cannot create controller'], LOGGERPRO_TAG);
                    raise EMVCException.Create(http_status.InternalServerError,
                      'Cannot create controller');
                  end;
                end;
                lRouterMethodToCallName := lRouter.MethodToCall.Name;
                lRouterControllerClazzQualifiedClassName := lRouter.ControllerClazz.QualifiedClassName;

                MVCFramework.Logger.InitThreadVars;

                lContext.fActionQualifiedName := lRouterControllerClazzQualifiedClassName + '.'+ lRouterMethodToCallName;
                lSelectedController.Engine := Self;
                lSelectedController.Context := lContext;
                lSelectedController.ApplicationSession := FApplicationSession;
                lContext.ParamsTable := lParamsTable;
                ExecuteBeforeControllerActionMiddleware(
                  lContext,
                  lRouterControllerClazzQualifiedClassName,
                  lRouterMethodToCallName,
                  lHandled);
                if lHandled then
                  Exit(True);

                lBodyParameter := nil;
                lSelectedController.MVCControllerAfterCreate;
                try
                  lHandled := False;
                  lSelectedController.ContentType := BuildContentType(lResponseContentMediaType,
                    lResponseContentCharset);
                  lActionFormalParams := lRouter.MethodToCall.GetParameters;
                  if (Length(lActionFormalParams) = 0) then
                    SetLength(lActualParams, 0)
                  else if (Length(lActionFormalParams) = 1) and
                    (SameText(lActionFormalParams[0].ParamType.QualifiedName,
                    'MVCFramework.TWebContext')) then
                  begin
                    SetLength(lActualParams, 1);
                    lActualParams[0] := lContext;
                  end
                  else
                  begin
                    FillActualParamsForAction(lSelectedController, lContext, lActionFormalParams,
                      lRouterMethodToCallName, lActualParams, lBodyParameter);
                  end;
                  lSelectedController.OnBeforeAction(lContext, lRouterMethodToCallName, lHandled);
                  if not lHandled then
                  begin
                    try
                      lRouter.MethodToCall.Invoke(lSelectedController, lActualParams);
                    finally
                      lSelectedController.OnAfterAction(lContext, lRouterMethodToCallName);
                    end;
                  end;
                finally
                  try
                    lBodyParameter.Free;
                  except
                    on E: Exception do
                    begin
                      LogE(Format('Cannot free Body object: [CLS: %s][MSG: %s]',
                        [E.Classname, E.Message]));
                    end;
                  end;
                  lSelectedController.MVCControllerBeforeDestroy;
                end;
                ExecuteAfterControllerActionMiddleware(lContext,
                  lRouterControllerClazzQualifiedClassName,
                  lRouterMethodToCallName,
                  lHandled);
                lContext.Response.ContentType := lSelectedController.ContentType;
                fOnRouterLog(lRouter, rlsRouteFound, lContext);
              end
              else // execute-routing
              begin
                if Config[TMVCConfigKey.AllowUnhandledAction] = 'false' then
                begin
                  lContext.Response.StatusCode := http_status.NotFound;
                  lContext.Response.ReasonString := 'Not Found';
                  fOnRouterLog(lRouter, rlsRouteNotFound, lContext);
                  raise EMVCException.Create(lContext.Response.ReasonString,
                    lContext.Request.HTTPMethodAsString + ' ' + lContext.Request.PathInfo, 0,
                    http_status.NotFound);
                end
                else
                begin
                  lContext.Response.FlushOnDestroy := False;
                end;
              end; // end-execute-routing
            end; // if not handled by beforerouting
          except
            on ESess: EMVCSessionExpiredException do
            begin
              if not CustomExceptionHandling(ESess, lSelectedController, lContext) then
              begin
                Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                  [ESess.Classname, ESess.Message, GetRequestShortDescription(ARequest),
                  ESess.DetailedMessage], LOGGERPRO_TAG);
                lContext.SessionStop;
                lSelectedController.ResponseStatus(ESess.HTTPErrorCode);
                lSelectedController.Render(ESess);
              end;
            end;
            on E: EMVCException do
            begin
              if not CustomExceptionHandling(E, lSelectedController, lContext) then
              begin
                Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                  [E.Classname, E.Message, GetRequestShortDescription(ARequest), E.DetailedMessage], LOGGERPRO_TAG);
                if Assigned(lSelectedController) then
                begin
                  lSelectedController.ResponseStatus(E.HTTPErrorCode);
                  lSelectedController.Render(E);
                end
                else
                begin
                  SendRawHTTPStatus(lContext, E.HTTPErrorCode,
                    Format('[%s] %s', [E.Classname, E.Message]), E.Classname);
                end;
              end;
            end;
            on EIO: EInvalidOp do
            begin
              if not CustomExceptionHandling(EIO, lSelectedController, lContext) then
              begin
                Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                  [EIO.Classname, EIO.Message, GetRequestShortDescription(ARequest), 'Invalid Op'], LOGGERPRO_TAG);
                if Assigned(lSelectedController) then
                begin
                  lSelectedController.ResponseStatus(http_status.InternalServerError);
                  lSelectedController.Render(EIO);
                end
                else
                begin
                  SendRawHTTPStatus(lContext, http_status.InternalServerError,
                    Format('[%s] %s', [EIO.Classname, EIO.Message]), EIO.Classname);
                end;
              end;
            end;
            on Ex: Exception do
            begin
              if not CustomExceptionHandling(Ex, lSelectedController, lContext) then
              begin
                Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                  [Ex.Classname, Ex.Message, GetRequestShortDescription(ARequest), 'Global Action Exception Handler'], LOGGERPRO_TAG);
                if Assigned(lSelectedController) then
                begin
                  lSelectedController.ResponseStatus(http_status.InternalServerError);
                  lSelectedController.Render(Ex);
                end
                else
                begin
                  SendRawHTTPStatus(lContext, http_status.InternalServerError,
                    Format('[%s] %s', [Ex.Classname, Ex.Message]), Ex.Classname);
                end;
              end;
            end;
          end;
          try
            ExecuteAfterRoutingMiddleware(lContext, lHandled);
          except
            on Ex: Exception do
            begin
              if not CustomExceptionHandling(Ex, lSelectedController, lContext) then
              begin
                Log.ErrorFmt('[%s] %s [PathInfo "%s"] (Custom message: "%s")',
                  [Ex.Classname, Ex.Message, GetRequestShortDescription(ARequest), 'After Routing Exception Handler'], LOGGERPRO_TAG);
                if Assigned(lSelectedController) then
                begin
                  { middlewares *must* not raise unhandled exceptions }
                  lSelectedController.ResponseStatus(http_status.InternalServerError);
                  lSelectedController.Render(Ex);
                end
                else
                begin
                  SendRawHTTPStatus(lContext, http_status.InternalServerError,
                    Format('[%s] %s', [Ex.Classname, Ex.Message]), Ex.Classname);
                end;
              end;
            end;
          end;
        finally
          FreeAndNil(lSelectedController);
        end;
      finally
        lRouter.Free;
      end;
    finally
      DoWebContextDestroyEvent(lContext);
      lContext.Free;
    end;
  finally
    lParamsTable.Free;
  end;
end;

首先判断请求内容的长度是否超长,FConfigCache_MaxRequestSize是配置常量,默认5MB(5*1024*1024, MVCFramework.Commons.pas 单元的 TMVCConstants结构),

lParamsTable: TMVCRequestParamsTable,只是TDictionary<string,string>别名。

MVCFrameWork框架有自己的一套 Context,Request,Response,均定义在MVCFramework.pas单元,TMVCWebRequest包装了系统的TWebRequest,TMVCWebResponse包装了系统的TWebResponse,TWebContext是重新定义的。

DefineDefaultResponseHeaders()定制默认的Header。

lRouter := TMVCRouter.Create(FConfig, gMVCGlobalActionParamsCache);

创建路由器,FConfig是Web配置,gMVCGlobalActionParamsCache参数是个全局线程安全对象,用于缓存动作参数列表。

ExecuteBeforeRoutingMiddleware(lContext, lHandled);

执行中间件的OnBeforeRouting(),然后开始执行路由lRouter.ExecuteRouting():


function TMVCRouter.ExecuteRouting(const ARequestPathInfo: string;
  const ARequestMethodType: TMVCHTTPMethodType;
  const ARequestContentType, ARequestAccept: string;
  const AControllers: TObjectList<TMVCControllerDelegate>;
  const ADefaultContentType: string;
  const ADefaultContentCharset: string;
  const APathPrefix: string;
  var ARequestParams: TMVCRequestParamsTable;
  out AResponseContentMediaType: string;
  out AResponseContentCharset: string): Boolean;
var
  LRequestPathInfo: string;
  LRequestAccept: string;
  LRequestContentType: string;
  LControllerMappedPath: string;
  LControllerMappedPaths: TStringList;
  LControllerDelegate: TMVCControllerDelegate;
  LAttributes: TArray<TCustomAttribute>;
  LAtt: TCustomAttribute;
  LRttiType: TRttiType;
  LMethods: TArray<TRttiMethod>;
  LMethod: TRttiMethod;
  LMethodPath: string;
  LProduceAttribute: MVCProducesAttribute;
  lURLSegment: string;
  LItem: String;
  // JUST FOR DEBUG
  // lMethodCompatible: Boolean;
  // lContentTypeCompatible: Boolean;
  // lAcceptCompatible: Boolean;
begin
  Result := False;

  FMethodToCall := nil;
  FControllerClazz := nil;
  FControllerCreateAction := nil;

  LRequestAccept := ARequestAccept;
  LRequestContentType := ARequestContentType;
  LRequestPathInfo := ARequestPathInfo;
  if (Trim(LRequestPathInfo) = EmptyStr) then
    LRequestPathInfo := '/'
  else
  begin
    if not LRequestPathInfo.StartsWith('/') then
    begin
      LRequestPathInfo := '/' + LRequestPathInfo;
    end;
  end;
  //LRequestPathInfo := TNetEncoding.URL.EncodePath(LRequestPathInfo, [Ord('$')]);
  LRequestPathInfo := TIdURI.PathEncode(Trim(LRequestPathInfo)); //regression introduced in fix for issue 492

  TMonitor.Enter(gLock);
  try
    //LControllerMappedPaths := TArray<string>.Create();
    LControllerMappedPaths := TStringList.Create;
    try
      for LControllerDelegate in AControllers do
      begin
        LControllerMappedPaths.Clear;
        SetLength(LAttributes, 0);
        LRttiType := FRttiContext.GetType(LControllerDelegate.Clazz.ClassInfo);

        lURLSegment := LControllerDelegate.URLSegment;
        if lURLSegment.IsEmpty then
        begin
          LAttributes := LRttiType.GetAttributes;
          if (LAttributes = nil) then
            Continue;
          //LControllerMappedPaths := GetControllerMappedPath(LRttiType.Name, LAttributes);
          FillControllerMappedPaths(LRttiType.Name, LAttributes, LControllerMappedPaths);
        end
        else
        begin
          LControllerMappedPaths.Add(lURLSegment);
        end;

        for LItem in LControllerMappedPaths do
        begin
          LControllerMappedPath := LItem;
          if (LControllerMappedPath = '/') then
          begin
            LControllerMappedPath := '';
          end;

    {$IF defined(TOKYOORBETTER)}
          if not LRequestPathInfo.StartsWith(APathPrefix + LControllerMappedPath, True) then
    {$ELSE}
          if not TMVCStringHelper.StartsWith(APathPrefix + LControllerMappedPath, LRequestPathInfo, True) then
    {$ENDIF}
          begin
            Continue;
          end;
//        end;

//          if (not LControllerMappedPathFound) then
//            continue;

          LMethods := LRttiType.GetMethods; { do not use GetDeclaredMethods because JSON-RPC rely on this!! }
          for LMethod in LMethods do
          begin
            if LMethod.Visibility <> mvPublic then // 2020-08-08
              Continue;
            if (LMethod.MethodKind <> mkProcedure) { or LMethod.IsClassMethod } then
              Continue;

            LAttributes := LMethod.GetAttributes;
            if Length(LAttributes) = 0 then
              Continue;

            for LAtt in LAttributes do
            begin
              if LAtt is MVCPathAttribute then
              begin
                // THIS BLOCK IS HERE JUST FOR DEBUG
                // if LMethod.Name.Contains('GetProject') then
                // begin
                // lMethodCompatible := True; //debug here
                // end;
                // lMethodCompatible := IsHTTPMethodCompatible(ARequestMethodType, LAttributes);
                // lContentTypeCompatible := IsHTTPContentTypeCompatible(ARequestMethodType, LRequestContentType, LAttributes);
                // lAcceptCompatible :=  IsHTTPAcceptCompatible(ARequestMethodType, LRequestAccept, LAttributes);

                if IsHTTPMethodCompatible(ARequestMethodType, LAttributes) and
                  IsHTTPContentTypeCompatible(ARequestMethodType, LRequestContentType, LAttributes) and
                  IsHTTPAcceptCompatible(ARequestMethodType, LRequestAccept, LAttributes) then
                begin
                  LMethodPath := MVCPathAttribute(LAtt).Path;
                  if IsCompatiblePath(APathPrefix + LControllerMappedPath + LMethodPath,
                    LRequestPathInfo, ARequestParams) then
                  begin
                    FMethodToCall := LMethod;
                    FControllerClazz := LControllerDelegate.Clazz;
                    FControllerCreateAction := LControllerDelegate.CreateAction;
                    LProduceAttribute := GetAttribute<MVCProducesAttribute>(LAttributes);
                    if LProduceAttribute <> nil then
                    begin
                      AResponseContentMediaType := LProduceAttribute.Value;
                      AResponseContentCharset := LProduceAttribute.Charset;
                    end
                    else
                    begin
                      AResponseContentMediaType := ADefaultContentType;
                      AResponseContentCharset := ADefaultContentCharset;
                    end;
                    Exit(True);
                  end;
                end;
              end; // if MVCPathAttribute
            end; // for in Attributes
          end; // for in Methods
        end;
      end; // for in Controllers
    finally
      LControllerMappedPaths.Free;
    end;
  finally
    TMonitor.Exit(gLock);
  end;
end;

对URL路由,URL参数等进行解析,找到当前执行的Controler及要执行的方法(Action)及参数等,

执行方法并返回客户端。

将结果返回客户端,有个专门的通用方法Render(),

TMVCRenderer = class(TMVCBase)

TMVCController = class(TMVCRenderer)

TMVCRenderer类里定义了各种各样的Render()方法,TMVCController是TMVCRenderer的子类,可以方便调用。

看几个Render()方法定义:

    procedure Render(const AContent: string); overload;
    procedure Render(const AStatusCode: Integer; const AContent: string); overload;
    procedure Render(const AStatusCode: Integer); overload;

.......................

    procedure Render(const AObject: TObject;
      const ASerializationAction: TMVCSerializationAction = nil;
      const AIgnoredFields: TMVCIgnoredList = nil); overload;
    procedure Render(const AObject: TObject; const AOwns: Boolean;
      const ASerializationAction: TMVCSerializationAction = nil;
      const AIgnoredFields: TMVCIgnoredList = nil); overload;

...............

这样的Render()方法有差不多30个...............

这里只是粗略介绍了DelphiMVCFrameWork框架,没有深入进去,后续再详细分析,比如认证授权、ORM等部分。

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

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

相关文章

Java每日一练(20230422)

目录 1. 拼接最大数 &#x1f31f;&#x1f31f;&#x1f31f; 2. Z 字形变换 &#x1f31f;&#x1f31f; 3. 跳跃游戏 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java…

su命令无权限,如何解决

正常情况下输入su命令执行如下 当遇到这种情况时别慌&#xff0c;很大概率是你还没连接Linux服务器。 在连接成功后&#xff0c;再尝试使用su命令成功的话&#xff0c;就会让你输入其他用户的密码。因为我只有一个普通用户和一个根目录&#xff0c;默认情况下是直接切换根用户。…

华为云企业快成长技术创新论坛全国巡演北京首站圆满落幕

4月15日&#xff0c;华为云联合msup举办的“企业快成长大数据技术创新论坛北京站”圆满举办&#xff0c;100余位来自全国各地的大数据技术总监/技术经理/研发工程师共聚一堂&#xff0c;共探数据湖的架构演进&#xff0c;数据治理方法论及最佳经验实践。 首先由华为云大数据人工…

APM/Air32F103/CH32F203/STM32F103程序互通说明

APM/Air32F103/CH32F203/STM32F103程序互通说明 ✨感觉国内中低端芯片就像 春秋时期&#xff0c;各诸侯群雄纷争的局面。各厂商都推出相关的替代竞品方案。这对于嵌入式开发从业者来说&#xff0c;有更多的开发方案可选。同时开发者不得不面对不同方案&#xff0c;项目移植工作…

724. 寻找数组的中心下标

力扣724. 寻找数组的中心下标 一、题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;请计算数组的 中心下标 。 数组 中心下标 是数组的一个下标&#xff0c;其左侧所有元素相加的和等于右侧所有元素相加的和。 如果中心下标位于数组最左端&#xff0c;那么左侧数之和…

express + TS :解决 TypeScript 报错:“无法重新声明块范围变量”的问题

问题描述 使用 Express TS 开发项目&#xff0c;在两个不同的文件引入相同的依赖&#xff0c;红色波浪线 虽然程序可正常运行 其他问题 无法重新声明块范围变量函数实现重复标识符重复 问题原因 项目中使用 CommonJS 规范&#xff0c;进行模块间的导入导出操作 因为在 Co…

八、Python结合Qt实现点击按钮保存并生成自定义word详细讲解(相信我,耐心看完,一定会有收获的)

一、需求介绍 因为我的毕设需要设计一个系统&#xff0c;然后把结果生成检测报告供企业下载。模型大概已经训练好了&#xff0c;也就差个导出word功能&#xff0c;把模型识别的数据结果输入到word导出即可。 二、最终实现效果 这里随便整个模板来对所需要的函数进行说明&…

Linux常用命令——iperf命令

在线Linux命令查询工具 iperf 网络性能测试工具 补充说明 iperf命令是一个网络性能测试工具。iperf可以测试TCP和UDP带宽质量。iperf可以测量最大TCP带宽&#xff0c;具有多种参数和UDP特性。iperf可以报告带宽&#xff0c;延迟抖动和数据包丢失。利用iperf这一特性&#x…

怎样搭建游戏服务器,传奇复古版手游是怎样搭建的,用云服务器架设游戏技术详细教程

本教程以战神传奇复古修复装备版为例&#xff1a; 本教程资源提供&#xff1a;海盗空间 --------------------------------------------------------------------------------------------------- 系统&#xff1a;Windows Server 2012 R2 x64 -----------------------------…

Python - 优先队列(queue.PriorityQueue heapq)

目录 什么是优先队列 为什么需要优先队列&#xff1f; 优先队列是个啥&#xff1f; 优先队列的工作原理 Python实现一个优先队列 Python内置库中的queue.PriorityQueue的使用 基本操作 多条件优先级实现 Python内置库中的heapq heapq的常用操作 基于heapq实现一个优…

通过AI生成的视频分发了难以检测的恶意软件加载程序

安全研究人员警告说&#xff0c;一种新的恶意软件加载程序被用作 Aurora 信息窃取程序感染链的一部分。 加载程序使用反虚拟机 (VM) 和不寻常的编译技术&#xff0c;这些技术似乎使其非常成功地避免了安全解决方案的检测。 Aurora 信息窃取器是用 Go 编写的&#xff0c;作为恶…

高速下载Arxiv论文的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

【微服务笔记19】微服务组件之Nacos注册中心基础环境搭建

这篇文章&#xff0c;主要介绍微服务组件之Nacos注册中心基础环境搭建。 目录 一、Nacos注册中心 1.1、Nacos注册中心 1.2、搭建NacosServer服务端 &#xff08;1&#xff09;下载Nacos Server服务端工程 &#xff08;2&#xff09;修改配置信息 &#xff08;3&#xff0…

【Hello Network】网络编程套接字(三)

作者&#xff1a;小萌新 专栏&#xff1a;网络 作者简介&#xff1a;大二学生 希望能和大家一起进步 本篇博客简介&#xff1a;简单介绍下各种类型的Tcp协议 各种类型Tcp服务器 多进程版的TCP网络程序捕捉SIGCHLD信号让孙子进程执行任务 多线程TCP网络程序线程池版多线程TCP网络…

Elasticsearch学习,请先看这篇!

目录 一、初始elasticsearch 1、概述 简介 发展 2、倒排索引 3、基本概念 文档 索引 Mysql和es的区别 4、分词器 初始分词器 Ik分词器-扩展词库 二、索引库操作 1、mapper属性 2、创建索引库 3、查询、删除索引库 三、文档操作 1、新增文档 2、查询、删除文档…

计算机网络科普

文章目录 1、集线器2、CSMA/CD协议3、交换机3.1 交换机的桥接 4、 路由器5、 路由表6、IP地址7、MAC地址8、ARP协议9、关于网络层次模型10、路由器 1、集线器 计算机之间的相互通信&#xff0c;你会怎么设计&#xff1f; 如果是两台计算机&#xff0c;之间拉一条线&#xff0c;…

ClickHouse性能优化

目录 1 Explain查看执行计划优化sql1.1 基本语法1.2 案例实操1.2.1 查看 PLAIN1.2.2 AST 语法树1.2.3 SYNTAX 语法优化1.2.4 查看 PIPELINE 2 ClickHouse建表优化2.1 数据类型2.1.1 时间字段的类型2.1.2 空值存储类型 2.2 分区和索引2.3 表参数2.4 写入和删除优化2.5 常见配置2…

分享一些提升效率的小工具

1、 IObit Uninstaller IObit Uninstaller是一款简单专业的卸载工具&#xff0c;可以帮我们卸载电脑中顽固难卸的软件和浏览器插件&#xff0c;支持强制一键卸载和文件粉碎功能。 除了卸载软件&#xff0c;它还可以自动帮我们检测软件安装、检测软件更新、查看工具栏和插件。 …

IDEA22.3.3的三个常用经常遇到的配置问题

1、期待效果&#xff1a;【打开iDEA的时候&#xff0c;让开发者选择需要打开的项目】 设置如下 2、期待效果&#xff1a;配置默认的Maven&#xff0c;避免每次新建项目后&#xff0c;都需要去修改Maven配置 同理&#xff0c;修改默认的java版本和自己本地java环境一致 3、新建…

数据库SQL语句优化技巧

当今世界&#xff0c;数据量不断增长&#xff0c;数据库的使用变得越来越普遍。虽然数据库提供了很多强大的功能&#xff0c;但是它们也需要被优化以确保它们的性能得到最大化。在本篇博客中&#xff0c;我们将探讨SQL语句优化的几种技巧&#xff0c;这些技巧可以帮助您提高数据…