SAP GUI Scripting - 如何判断组件是否存在
总体来说,SAP Scripting 与 BDC 类似,因为是屏幕录制,就可能碰到不同的情况,比如每个录入的数据不同,可能出现一个对话框,或者出现一个状态栏消息。这种任何有变化的情况,在 Scripting 中没有考虑到,就会导致操作失败。本文以导入 MR21 物料价格为例,演示如何处理组件/控件不存在的情况。
基于连续性,如何使用 SAP SAP Scripting 的要点,请参考本人之前的博文:
SAP Scripting Tracker基本使用技巧-CSDN博客
SAP Scripting Tracker基本使用技巧(续)_sap tracker-CSDN博客
SAP Scripting Tracker基本使用技巧 - VBA 示例-CSDN博客
首先使用 SAP Scripting Tracker 基于 Basic 录制 MR21 修改物料价格,得到下面的代码:
session.findById("wnd[0]").resizeWorkingPane(116, 39, vbFalse)
session.findById("wnd[0]/tbar[0]/okcd").text = "MR21"
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/ctxtMR21HEAD-BUDAT").text = "2024.12.31"
session.findById("wnd[0]/usr/ctxtMR21HEAD-BUKRS").text = "3600"
session.findById("wnd[0]/usr/ctxtMR21HEAD-WERKS").text = "3601"
session.findById("wnd[0]/usr/txtMR21HEAD-XBLNR").setFocus
session.findById("wnd[0]/usr/txtMR21HEAD-XBLNR").caretPosition = 0
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").text = "20000239"
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").caretPosition = 8
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").text = "100"
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").setFocus
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").caretPosition = 3
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").setFocus
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").caretPosition = 4
session.findById("wnd[0]/tbar[0]/btn[11]").press
录制过程中,为方便后续对代码的理解,可以在关键点插入空行,或插入空行并加上注释。因为最终需要从 Excel 的单元格导入数据,所以接下来对代码进行微调,将写死的部分替换为单元格。我一般先定义一个起始的单元格,然后其他单元格都替换为基于起始单元格的 offset:
Dim leftCell As Range
Set leftCell = Sheet1.Range("A" & i)session.findById("wnd[0]").resizeWorkingPane(116, 39, vbFalse)
session.findById("wnd[0]/tbar[0]/okcd").text = "MR21"
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/ctxtMR21HEAD-BUDAT").text = leftCell.Offset(0, 2).Value ' 过账日期
session.findById("wnd[0]/usr/ctxtMR21HEAD-BUKRS").text = leftCell.Value ' 公司代码
session.findById("wnd[0]/usr/ctxtMR21HEAD-WERKS").text = leftCell.Offset(0, 1).Value ' 工厂
session.findById("wnd[0]/usr/txtMR21HEAD-XBLNR").setFocus
session.findById("wnd[0]/usr/txtMR21HEAD-XBLNR").caretPosition = 0
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").text = leftCell.Offset(0, 3).Value ' 物料编码
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").caretPosition = 8
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").text = leftCell.Offset(0, 4).Value '新价格
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").setFocus
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").caretPosition = 3
session.findById("wnd[0]").sendVKey(0)session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").setFocus
session.findById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").caretPosition = 4
session.findById("wnd[0]/tbar[0]/btn[11]").press
正常情况下,这个脚本就可以用了。本来 MR21 是一个表格式界面,可以处理多条记录,但 Scripting 是通过位置索引来表达某个单元格,因为项目物料不是很多,所以采取简单的方式,每一条记录保存之后再录入下一个物料,就解决了这个问题。
但物料本身的数据存在差异,录入的时候会碰到不同的情况,比如有些物料本身已经有将来或当前的价格,有些物料在修改的时候,如果新价格等于老价格,SAP就会在状态栏有一个提示:对于XXX物料,价格没有变化。对这种的情况,如果不处理,VBA 会抛出异常,所以需要处理。
我们先来讲怎样通过 Scripting Tracker 查看这个控件。在查看之前,需要制造出抛出异常的情景。

然后刷新 Scripting Tracker,显示控件的 ID:

有了这个 ID 之后,我们可以通过两个方法来处理,推荐的是第二个方法。
方法1
Dim msg As String
On Error Resume Next
msg = session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1") '价格没有修改对话框
If Err.Number = 0 ThenleftCell.Offset(0, 5).Value = session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1").Text
End If
方法2
第二个参数为 False。
Public Function FindById( _ByVal Id As String, _Optional ByVal Raise As Variant _
) As GuiComponent
在对象的子对象中搜索给定的 ID。如果参数是完全限定的 ID,函数将首先检查容器对象的 ID 是否是 ID 参数的前缀。如果是这种情况,这个前缀将被截断。如果找不到具有给定 ID 的后代,除非将可选参数 raise 设置为 False,否则函数将引发异常。(Search through the object’s descendants for a given id. If the parameter is a fully qualified id, the function will first check if the container object’s id is a prefix of the id parameter. If that is the case, this prefix is truncated. If no descendant with the given id can be found the function raises an exception unless the optional parameter raise is set to False.)
API 可以参考:GuiContainer Object | SAP Help Portal
If Not session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1", False) Is Nothing Then '价格没有修改对话框leftCell.Offset(0, 5).Value = session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1").Text
Else' 读取返回值leftCell.Offset(0, 5).Value = session.FindById("wnd[0]/sbar").Text
End If
最后给出 Excel 界面和完整的代码。

SapSesion.bas
Option ExplicitPublic Function GetSession() As ObjectDim SapGuiAuto As ObjectDim app As SAPFEWSELib.GuiApplicationDim connection As SAPFEWSELib.GuiConnectionDim session As SAPFEWSELib.GuiSessionIf app Is Nothing ThenSet SapGuiAuto = GetObject("SAPGUI")Set app = SapGuiAuto.GetScriptingEngineEnd IfIf connection Is Nothing ThenSet connection = app.Children(0)End IfIf session Is Nothing ThenSet session = connection.Children(0)End IfSet GetSession = session
End FunctionPublic Sub returnEasyAccess(sess As Object)sess.FindById("wnd[0]/tbar[0]/okcd").Text = "/n"sess.FindById("wnd[0]").SendVKey (0)
End Sub'Public Sub test()
' Dim s As Object
' Set s = GetSession
'
' returnEasyAccess s
'End Sub
DataImport.bas
Option ExplicitPublic Sub DataImport()Dim session As ObjectSet session = GetSession' 确认If Not msgbox("脚本将对当前打开的SAP系统进行更改物料价格更改,请不要随意点击执行。是否继续?", vbYesNo + vbExclamation) = vbYes ThenExit SubEnd IfDim pwd As Stringpwd = InputBox("请输入密码")If pwd = "" ThenExit SubEnd IfIf pwd <> "stonestone" Thenmsgbox "密码不正确"Exit SubEnd IfCall returnEasyAccess(session)'==================================' 执行'==================================Dim i As LongFor i = 4 To Sheet1.UsedRange.CountIf Sheet1.Range("A" & i).Value = "EOF" Then Exit Sub' 每次先回到Easy Access 界面Call returnEasyAccess(session)Dim leftCell As RangeSet leftCell = Sheet1.Range("A" & i)session.FindById("wnd[0]").Maximize' 功能代码'=======================================================================session.FindById("wnd[0]/tbar[0]/okcd").Text = "MR21"session.FindById("wnd[0]").SendVKey (0)session.FindById("wnd[0]/usr/ctxtMR21HEAD-BUDAT").Text = leftCell.Offset(0, 2).Value ' 过账日期session.FindById("wnd[0]/usr/ctxtMR21HEAD-BUKRS").Text = "3600" ' 公司代码session.FindById("wnd[0]/usr/ctxtMR21HEAD-WERKS").Text = leftCell.Offset(0, 1).Value ' plantsession.FindById("wnd[0]/usr/ctxtMR21HEAD-WERKS").SetFocussession.FindById("wnd[0]/usr/ctxtMR21HEAD-WERKS").CaretPosition = 4session.FindById("wnd[0]").SendVKey (0)session.FindById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").Text = leftCell.Offset(0, 3).Value ' 物料编码session.FindById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/ctxtCKI_MR21_0250-MATNR[0,0]").CaretPosition = 8session.FindById("wnd[0]").SendVKey (0)'如果物料有将来价格则存在对话框If Not session.FindById("wnd[1]/tbar[0]/btn[0]", False) Is Nothing Thensession.FindById("wnd[1]/tbar[0]/btn[0]").PressEnd Ifsession.FindById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").Text = leftCell.Offset(0, 4).Value '新价格session.FindById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").SetFocussession.FindById("wnd[0]/usr/tabsMR21_TABSTRIP/tabpTAB1/ssubMR21_SUB:SAPRCKM_MR21:0250/tblSAPRCKM_MR21MR21_TABCONTROL/txtCKI_MR21_0250-NEWVALPR[4,0]").CaretPosition = 4session.FindById("wnd[0]").SendVKey (0)' Savesession.FindById("wnd[0]/tbar[0]/btn[11]").Press' Save之后可能提示物料价格没有更改If Left(session.FindById("wnd[0]/sbar").Text, 4) = "对于物料" Thensession.FindById("wnd[0]").SendVKey (0)End If'====================================================================If Not session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1", False) Is Nothing Then '价格没有修改对话框leftCell.Offset(0, 5).Value = session.FindById("/app/con[0]/ses[0]/wnd[1]/usr/txtMESSTXT1").TextElse' 读取返回值leftCell.Offset(0, 5).Value = session.FindById("wnd[0]/sbar").TextEnd If' 保存If i Mod 5 = 0 ThenThisWorkbook.SaveEnd If' 滚动If i >= 25 ThenActiveWindow.SmallScroll down:=1End IfNext
End Sub相关文章:
SAP GUI Scripting - 如何判断组件是否存在
总体来说,SAP Scripting 与 BDC 类似,因为是屏幕录制,就可能碰到不同的情况,比如每个录入的数据不同,可能出现一个对话框,或者出现一个状态栏消息。这种任何有变化的情况,在 Scripting 中没有考…...
Go 计算Utf8字符串的长度 不要超过mysql字段的最大长度
背景: 我有一个mysql的字段,是utf8格式的,但有时候前端传的字符串会超长,为此我需要在后端接口,先判断是否超长,如果超长,则报错提示前端。 代码: // 计算utf8下,字符串…...
llamafactory报错:双卡4090GPU,训练qwen2.5:7B、14B时报错GPU显存不足(out of memory),轻松搞定~~~
实际问题场景: 使用llamafactory进行微调qwen2.5 7B和14B的大模型时,会出现out of memory的报错。尝试使用降低batch_size(原本是2,现在降到1)的方式,可以让qwen2.5:7B跑起来,但时不时会不稳定…...
全局webSocket 单个页面进行监听并移除单页面监听
之前全局封装的 webSocket 在某些特定的页面中使用会直接去调用 webSocket 的 onMessage 方法 已进入页面就会调,如果退出页面移除整个监听的话全局监听就会被移除 这是修改后的 全局封装 let token uni.getStorageSync(token) const HEARTBEAT_INTERVAL 1 *…...
JVM调优实践篇
理论篇 1多功能养鱼塘-JVM内存 大鱼塘O(可分配内存): JVM可以调度使用的总的内存数,这个数量受操作系统进程寻址范围、系统虚拟内存总数、系统物理内存总数、其他系统运行所占用的内存资源等因素的制约。 小池塘A&a…...
【JavaEE】Spring Web MVC
目录 一、Spring Web MVC简介 1.1 MVC简介1.2 Spring MVC1.3 RequestMapping注解1.3.1 使用1.3.2 RequestMapping的请求设置 1.3.2.1 方法11.3.2.2 方法2 二、Postman介绍 2.1 创建请求2.2 界面如下:2.3 传参介绍 一、Spring Web MVC简介 官方文档介绍ÿ…...
VSCode 插件开发实战(七):插件支持了哪些事件,以及如何利用和监听这些事件
前言 VSCode 作为现代开发者的首选编辑器之一,其核心优势在于其高度可扩展性。通过自定义插件,开发者可以根据自己的需求对编辑器进行功能扩展和优化。在这些插件开发过程中,事件处理和监听机制尤为重要,它们允许插件在特定事件发…...
指针详解之 多层嵌套的关系
1 例子之指向3个字符串的指针数组,易混淆! 1.1过程详解: char *str[3]{ "Hello,thisisasample!", "Hi,goodmorning.", "Helloworld" }; char s[80]; strcpy(s,str[0]); //也可写成strcpy(s,*st…...
Animated Drawings:让纸上的角色动起来
前言 今天介绍的这个工具非常的有意思:它可以让我们在纸上绘画的角色动起来。先一起来看看效果: 准备 首先,我们先准备一张绘画。可以在纸上进行绘制,也可以在电子设备上进行绘制。绘制内容不限,在这里为了方便演示&am…...
技术与教育的结合:高校听课评价系统的设计与实施
3.1系统可行性分析 需要使用大部分精力开发的高校听课评价系统为了充分降低开发风险,特意在开发之前进行可行性分析这个验证系统开发是否可行的步骤。本文就会从技术角度,经济角度,还有用户使用的程序的运行角度进行综合阐述。 3.1.1 技术可行…...
web移动端项目常用解决方案
移动端总会遇到一系列特定于移动设备的问题,分享下常见的移动端常见问题的处理方案。 1px边框问题 在高清屏幕下,1px的边框显示得比较粗。 .border-1px {position: relative; } .border-1px::after {position: absolute;content: ;width: 200%;height:…...
LabVIEW软件项目设计方案如何制定
制定LabVIEW软件项目设计方案需要综合考虑需求分析、架构设计、功能模块划分和时间预算等多个方面,确保项目开发过程高效、可控且最终满足目标要求。以下是一个详细的制定流程: 1. 需求分析 目标定义:明确项目的目标,例如数据采…...
数据结构(Java)——链表
1.概念及结构 链表是一种 物理存储结构上非连续 存储结构,数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的 。 2.分类 链表的结构非常多样,以下情况组合起来就有 8 种链表结构: (1)单向或者双向 (…...
变量与数据类型 - 整型、浮点型、字符型等
引言 在编程中,变量和数据类型是基础中的基础。理解它们如何工作以及如何正确使用它们对于编写高效且无误的代码至关重要。本文将详细介绍 C 中的几种基本数据类型:整型、浮点型、字符型等,并通过实例帮助读者更好地理解和掌握这些概念。 一…...
MacOS安装Xcode(非App Store)
文章目录 访问官网资源页面 访问官网资源页面 直接访问官网的历史版本下载资源页面地址:https://developer.apple.com/download/more/完成APP ID的登陆,直接找到需要的软件下载即可 解压后,安装将xcode.app移动到应用程序文件夹。...
运行Zr.Admin项目(后端)
1.下载Zr.Admin代码压缩包 https://codeload.github.com/izhaorui/Zr.Admin.NET/zip/refs/heads/main 2.打开项目 我这里装的是VS2022社区版 进入根目录,双击ZRAdmin.sln打开项目 3.安装.net7运行时 我当时下载的代码版本是.net7的 点击安装 点击安装࿰…...
Ubuntu24.04最新版本安装详细教程
Ubuntu 24.04 LTS发布说明 推荐的系统配置要求: 双核2 GHz处理器或更高 4 GB系统内存 25 GB磁盘存储空间 可访问的互联网 光驱或USB安装介质 Ubuntu 24.04官方下载网址:https://cn.ubuntu.com/download/desktop 04. Ubuntu 22.04(创建虚拟机方式一) 4…...
js版本之ES6特性简述【Proxy、Reflect、Iterator、Generator】(五)
目录 Proxy Reflect 静态方法 部分实例 Iterator 实际开发迭代器的使用实例 迭代器(Iterator)应用 Generator Proxy Proxy 是 ES6 中新增的对象 Proxy 是JavaScript中的内置对象,它提供了一种机制,可以拦截并自定义各种…...
CSS实现一个自定义的滚动条
要使用CSS创建一个自定义的滚动条,你可以使用伪元素和CSS的伪类来控制滚动条的外观和行为。以下是一个简单的例子,展示如何为任何HTML元素添加一个自定义的滚动条样式: <!DOCTYPE html> <html lang"en"> <head> …...
CKA认证 | Day8 K8s安全
第八章 Kubernetes安全 1、Kubernetes RBAC授权 Kubernetes 基于角色的访问控制(Role-Based Access Control, RBAC) 是一种强大的权限管理机制,用于控制用户、用户组、服务账户对 Kubernetes 集群资源的访问。通过 RBAC,可以细…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
Java数组Arrays操作全攻略
Arrays类的概述 Java中的Arrays类位于java.util包中,提供了一系列静态方法用于操作数组(如排序、搜索、填充、比较等)。这些方法适用于基本类型数组和对象数组。 常用成员方法及代码示例 排序(sort) 对数组进行升序…...
41道Django高频题整理(附答案背诵版)
解释一下 Django 和 Tornado 的关系? Django和Tornado都是Python的web框架,但它们的设计哲学和应用场景有所不同。 Django是一个高级的Python Web框架,鼓励快速开发和干净、实用的设计。它遵循MVC设计,并强调代码复用。Django有…...
Yii2项目自动向GitLab上报Bug
Yii2 项目自动上报Bug 原理 yii2在程序报错时, 会执行指定action, 通过重写ErrorAction, 实现Bug自动提交至GitLab的issue 步骤 配置SiteController中的actions方法 public function actions(){return [error > [class > app\helpers\web\ErrorAction,],];}重写Error…...
