当前位置: 首页 > article >正文

python oa服务器巡检报告脚本的重构和修改(适应数盾OTP)有空再去改

Two-Step Vertification required:

Please enter the mobile app OTPverification code:

01.因为巡检的服务器要双因子认证登录,也就是登录堡垒机时还要输入验证码。这对我的巡检查服务器的工作带来了不便。它的机制是每一次登录,算一次会话,每次会话要输入一次验证码。

总共5台服务器,每个服务器执行5个常规命令,其中一个服务器执行一个特殊命令 5*5+1=26
那么我就要输入26次验证码,验证码每30秒变更一次。每个验证码能用2,3次。

02.验证码肯定要输入的,那么就输入一次,把所有命令操作打包成一次会话执行所有命令,命令包含回车等操作符。

把命令放在列表中,当然用循环拼接字符串,一个一个写也可以,但太长可能会写错。

不讲这么多,上脚本主题

# #-*-coding:utf-8-*-
'''000.导入包'''
#001.把字符串变列表的包
from posixpath import split
#002.SSH连接堡垒机,输入命令返回结果到txt文件的包
import util.exe_ssh as es 
#003.构建截图窗口的包
import util.ssh_windows as sw
#004.向巡检报告插入图片的包
import util.insert_image as ii
#005.删除txt,png的包
import util.dele_file as df
#006.多线程的包
import threading
#007.时间的包
import time
#008.存储ip,端口,账号,密码,文件地址信息的类
import entity.ssh_info as si
#009.创建命令列表的类
import util.create_command_list as ccl


'''100.变量'''
#101.获取当天的年月日
current_time = time.strftime('%Y-%m-%d',time.localtime(time.time()))
#102.我所有登录信息话在ssh_access类里面,通过对象调用变量参数
ssh_obj = si.ssh_access()
#103.单纯文件名
file_name = ssh_obj.file_name
#104.文件的后序docx#
seq_name = ssh_obj.seq_name
#105.存放巡检报告的目录
default_path = ssh_obj.default_path
#106.巡检报告模板的地址
origen_path = default_path+"\\"+file_name+seq_name
#107.重命名巡检模板的巡检报告的地址
rename_path = default_path+"\\"+current_time+"\\"+file_name+current_time+seq_name
#108.putty,因为做一个假的putty窗口,putty图标的位置
icon_path=ssh_obj.icon_path
#109.存放命令返回结果txt文件的目录位置
txt_path=ssh_obj.txt_path
#110.访问堡垒机的ip地址
ip = ssh_obj.ip
#111.访问堡垒机的端口
port=ssh_obj.port
#112.访问堡垒机的账号
account=ssh_obj.account
#113.访问堡垒机的密码
pwd=ssh_obj.pwd
#114.服务器ip地址的列表





#存ip的列表
fwq_name = [] 
for value in ssh_obj.ip_dic.values():
    fwq_name.append(value)
print("fwq_name的内容")
print(fwq_name)
#115.存放需要命令的列表
fwq_command=ssh_obj.command_list
# print("fwq_command的内容")
print(fwq_command)
#116.服务器中文搜索的列表
fwq_search_name=[]
for key in ssh_obj.ip_dic.keys():
    fwq_search_name.append(key)
# print("fwq_search_name的内容")
# print(fwq_search_name)

#117.存放写入txt的目录
fwq_pre_txt_address = ssh_obj.fwq_pre_txt_address
# print("fwq_pre_txt_address的内容")
# print(fwq_pre_txt_address)
#118.存放截图的目录
fwq_pre_img_address = ssh_obj.fwq_pre_img_address

'''200.业务代码'''
#连接堡垒机,SSH连接返回命结果
'''服务器的中文名'''
#fwq_search_name
'''服务器的命令'''
#fwq_command
'''服务器的ip地址'''
#fwq_name
'''命令结果输出到txt的目录地址'''

full_fwq_name_command_list=ccl.get_fwq_full_name_command_list(fwq_search_name,fwq_command)
#20241121
es.command2txt(ip,
               port,
               account,
               pwd,
               fwq_name,
               full_fwq_name_command_list,
               txt_path,
               fwq_pre_txt_address)



#202.遍历截图
sw.show_windows_loop(fwq_pre_txt_address,fwq_pre_img_address,icon_path)    
#203.遍历插入图片
ii.table_insert_img_loop(rename_path,fwq_pre_img_address)    

#把生成png图片删除
df.del_file(fwq_pre_img_address)     
#把生成txt文件删除
df.del_file(txt_path)

我主要是对正面的包进行修改

#001.SSH连接堡垒机,输入命令返回结果到txt文件的包

import util.exe_ssh as es

# coding: utf-8
'''000.导入包'''
#001.用来休眠1秒的包
import time
#002.这个是访问堡垒机的包
import paramiko
#003.获取目录中所有文件名的包
import util.return_dir_file_name as rdf
#004.用于删除文件
import os 
#005.创建相同长度的数字字符串列表的包
import util.create_number_order as cno
#006.删除特定字符串前的字符串的包
import util.delete_before_string as dbs
#007.操作txt文件的包,里面写了两个方法,一个是把两个txt文件合并,一个是地址拼接前面加一些东西
import util.txt_util as tu

'''100.变量'''
#101.服务器账号前序
account_imf=['[root@oaapp02 ~]# ',
            '[root@oaapp01 ~]# ',
            '[root@bang01 ~]# ',
            '[root@rac1 ~]# ',
            '[root@rac2 ~]# ']
#102.txt的文件名列表,用于对指定txt文件进行操作
keywords_01 = ["01", "12", "23","34","45",'56']
keywords_2=["03","05","07","09"]
keywords_3=["14","16","18","20"]
keywords_4=["25","27","29","31"]
keywords_5=["36","38","40","42"]
keywords_6=["47","49","51","53"]

'''200.方法'''
#201.把命令执行结果写入txt文件的方法
def command2txt(ip,                 #ip不变的
                port,               #端口不变的
                account,            #用户名不变的
                pwd,                #密码不变的
                fwq_name,         #服务器ip的列表
                commands,         #不是单个命令,而是接收一个命令列表   
                txt_path,             
                txt_address         #txt的地址列表
                ):
    
    #202.获取私钥
    pkey=paramiko.RSAKey.from_private_key_file("C:\\Users\\human\\.ssh\\id_rsa",password=pwd)
    #203.paramiko SSH对象
    client = paramiko.SSHClient()
    #204.自动将服务器的公钥添加到known_hosts文件,并接受公钥。
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    #205.连接堡垒机
    client.connect(hostname=ip,port=port,username=account,pkey=pkey,timeout=60)
    #206.创建发送命令的对象
    shell = client.invoke_shell()
    #207.生成00-99的字符串列表
    number_list=cno.create_hundred_order_list(99)
    # print(number_list)
    #208.设置计数器count,拼设置初值为0
    count=0
    #209.遍历里面的命令
    for comand in commands:
        #210.用下标控制获取数字
        n=number_list[count]
        # print(n)
        #211.发送命令
        shell.send(comand)
        #212.如果准备就pass跳过
        while not shell.recv_ready():
            pass
        #213.睡眠0.5秒,模仿人操作
        time.sleep(0.5)
        #214.如果命令是'/',则跳过
        if comand == '/':
            continue
        #215.如果命令是搜索的堡垒机的字符串,则跳过
        elif comand in ('应用服务器02','应用服务器03','应用服务器01','数据库1','数据库2'):
            continue
        #216.过滤完执行下面的
        else:
            #217.接收命令执行结果
            stdout = shell.recv(10240)
            #218.对结果进行解码
            longstring = stdout.decode('utf-8')
            #219.如果结果包含"连用云",则跳过
            if "连用云" in longstring:
               continue
            #220.如果结果包含"exit",则跳过
            elif "exit" == longstring:
               continue
            else:
                #221.将结果写入txt文件
                with open(txt_address+n+".txt",'w') as f:
                    print(longstring,file = f)
                #222.计数器加1
                count+=1

    #223.获取目录中的文件名列表    
    file_name_list=rdf.re_file_name_list(txt_path)
    # print(file_name_list)
    #224.删除开头没有用的txt文件
    for f in file_name_list:
        print("f的值")
        print(f)
        keywords = ["00", "11", "22","33","44","55"]
        if any(keyword in f for keyword in keywords):
            os.remove(txt_path+"\\"+f)
    #225.删除完文件再获取目录中的文件名列表
    file_name_list=rdf.re_file_name_list(txt_path)
    #226.删除登录每个服务器txt文件开头的一些内容
    for f in file_name_list:
        # print("f的值")
        # print(f)
        #227.
        if any(keyword in f for keyword in keywords_01):
            # os.remove(txt_path+"\\"+f)
            with open(txt_path+"\\"+f, 'r') as file:
                content = file.read()
                if '56' in f:
                    content = dbs.dele_before_str(content,'[root')
                    with open(txt_path+"\\"+f, 'w') as file:
                        file.write(content)

                else: 
                    content = dbs.dele_before_str(content,'[root').replace("--color=never","")
                    with open(txt_path+"\\"+f, 'w') as file:
                        file.write(content)
        
       #删除完再获取
    for f in file_name_list:
        if any(keyword in f for keyword in keywords_2):  
                with open(txt_path+"\\"+f, 'r') as file:
                    content = file.read()
                    content = account_imf[0]+content
                with open(txt_path+"\\"+f, 'w') as file:
                    file.write(content)
    for f in file_name_list:
        if any(keyword in f for keyword in keywords_3):  
                with open(txt_path+"\\"+f, 'r') as file:
                    content = file.read()
                    content = account_imf[1]+content
                with open(txt_path+"\\"+f, 'w') as file:
                    file.write(content)
    for f in file_name_list:
        if any(keyword in f for keyword in keywords_4):  
                with open(txt_path+"\\"+f, 'r') as file:
                    content = file.read()
                    content = account_imf[2]+content
                with open(txt_path+"\\"+f, 'w') as file:
                    file.write(content)
    for f in file_name_list:
        if any(keyword in f for keyword in keywords_5):  
                with open(txt_path+"\\"+f, 'r') as file:
                    content = file.read()
                    content = account_imf[3]+content
                with open(txt_path+"\\"+f, 'w') as file:
                    file.write(content)
    for f in file_name_list:
        if any(keyword in f for keyword in keywords_6):  
                with open(txt_path+"\\"+f, 'r') as file:
                    content = file.read()
                    content = account_imf[4]+content
                with open(txt_path+"\\"+f, 'w') as file:
                    file.write(content)
   
    file_name_list=rdf.re_file_name_list(txt_path)
    
    # print("fwq_name的值")                
    # print(fwq_name)

    for ip_name in fwq_name:
    
        if ip_name==fwq_name[0]:
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[0]),
                       tu.add_pre_txt_address(file_name_list[1]),
                       tu.add_pre_txt_address(ip_name+"-0.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[2]),
                       tu.add_pre_txt_address(file_name_list[3]),
                       tu.add_pre_txt_address(ip_name+"-1.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[4]),
                       tu.add_pre_txt_address(file_name_list[5]),
                       tu.add_pre_txt_address(ip_name+"-2.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[6]),
                       tu.add_pre_txt_address(file_name_list[7]),
                       tu.add_pre_txt_address(ip_name+"-3.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[8]),
                       tu.add_pre_txt_address(file_name_list[9]),
                       tu.add_pre_txt_address(ip_name+"-4.txt"))
        elif ip_name==fwq_name[1]:
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[10]),
                       tu.add_pre_txt_address(file_name_list[11]),
                       tu.add_pre_txt_address(ip_name+"-0.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[12]),
                       tu.add_pre_txt_address(file_name_list[13]),
                       tu.add_pre_txt_address(ip_name+"-1.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[14]),
                       tu.add_pre_txt_address(file_name_list[15]),
                       tu.add_pre_txt_address(ip_name+"-2.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[16]),
                       tu.add_pre_txt_address(file_name_list[17]),
                       tu.add_pre_txt_address(ip_name+"-3.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[18]),
                       tu.add_pre_txt_address(file_name_list[19]),
                       tu.add_pre_txt_address(ip_name+"-4.txt"))
        elif ip_name==fwq_name[2]:
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[20]),
                       tu.add_pre_txt_address(file_name_list[21]),
                       tu.add_pre_txt_address(ip_name+"-0.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[22]),
                       tu.add_pre_txt_address(file_name_list[23]),
                       tu.add_pre_txt_address(ip_name+"-1.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[24]),
                       tu.add_pre_txt_address(file_name_list[25]),
                       tu.add_pre_txt_address(ip_name+"-2.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[26]),
                       tu.add_pre_txt_address(file_name_list[27]),
                       tu.add_pre_txt_address(ip_name+"-3.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[28]),
                       tu.add_pre_txt_address(file_name_list[29]),
                       tu.add_pre_txt_address(ip_name+"-4.txt"))
        elif ip_name==fwq_name[3]:
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[30]),  
                      tu.add_pre_txt_address(file_name_list[31]),
                       tu.add_pre_txt_address(ip_name+"-0.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[32]),
                       tu.add_pre_txt_address(file_name_list[33]),
                       tu.add_pre_txt_address(ip_name+"-1.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[34]),
                       tu.add_pre_txt_address(file_name_list[35]),
                       tu.add_pre_txt_address(ip_name+"-2.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[36]),
                       tu.add_pre_txt_address(file_name_list[37]),
                       tu.add_pre_txt_address(ip_name+"-3.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[38]),
                       tu.add_pre_txt_address(file_name_list[39]),
                       tu.add_pre_txt_address(ip_name+"-4.txt"))
        
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[-3]),
                       tu.add_pre_txt_address(file_name_list[-2]),
                       tu.add_pre_txt_address(ip_name+"-5.txt"))
            
        elif ip_name==fwq_name[4]:
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[40]),
                       tu.add_pre_txt_address(file_name_list[41]),
                       tu.add_pre_txt_address(ip_name+"-0.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[42]),
                       tu.add_pre_txt_address(file_name_list[43]),
                       tu.add_pre_txt_address(ip_name+"-1.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[44]),
                       tu.add_pre_txt_address(file_name_list[45]),
                       tu.add_pre_txt_address(ip_name+"-2.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[46]),
                       tu.add_pre_txt_address(file_name_list[47]),
                       tu.add_pre_txt_address(ip_name+"-3.txt"))
            tu.conbine_txt(tu.add_pre_txt_address(file_name_list[48]),
                       tu.add_pre_txt_address(file_name_list[49]),
                       tu.add_pre_txt_address(ip_name+"-4.txt"))

        #删除00-55的txt文
    for f in file_name_list:
        print("f的值")
        print(f)
        # keywords = ["00", "11", "22","33","44","55"]
        if any(keyword in f for keyword in number_list):
            os.remove(txt_path+"\\"+f)

07.创建列表命令列表的包,用于生成一个会话完成所有命令列表

#007.创建命令列表的包
import util.create_command_list as ccl

# #-*-coding:utf-8-*-
def get_fwq_full_name_command_list(fwq_search_name,command_list):
    full_name_command_list=[]
    exit_list=['exit',chr(0x0D)]
    for fwq_name in fwq_search_name:
        fwq_name_command=[chr(0x2F),fwq_name,chr(0x0D),chr(0x0D)]
        fwq_full_command_list=[]
        for command in command_list:
            fwq_command=[command,chr(0x0D)]
            fwq_full_command_list+=fwq_command
            # print(fwq_command_command)
        full_command_list=fwq_name_command+fwq_full_command_list
        full_name_command_list+=(full_command_list+exit_list)
    special_comand_list=[chr(0x2F),
                         '数据库1',
                         chr(0x0D),
                         chr(0x0D),
                         'su - grid asmcmd lsdg',
                         chr(0x0D),
                         chr(0x0D)]
    full_name_command_list+=special_comand_list
    print(full_name_command_list) 
    return full_name_command_list

执行的结果 

#003.构建截图窗口的包

import util.ssh_windows as sw

这里使用多线程,一个方法是截图,一个方法是显示虚假的putty命令窗口界面

'''000.导入包'''
#001.生成python交换窗口的包
import tkinter as tk
#002.屏幕截图的包
import util.screen_catch as sc
#003.用来体眠时间包
import time 
#004.多线程包
import threading
#005.返回目录的文件名的包
import util.return_dir_file_name as rf
#006.左对齐的包
from turtle import left
#007.日期时间的包
from datetime import datetime
#file_path 打开路径
#title     窗口的标题
#icon_path 窗口图标的路径
'''100.方法'''
#101.txt的文件名,putty窗口的标题,putty窗口的图标
def show_windows(file_path,title,icon_path):
    print("show_windows:"+str(datetime.now()))#显示一下时间
    #打开txt文档读取内容
    file_handle = open(file_path,mode = 'r')
    content = file_handle.read()
    root = tk.Tk()
    #弹出窗口在最上层显示
    root.attributes("-topmost",1)
    root.after(3000, root.destroy)#放在这里才能生效 3秒后窗口关闭 关闭完一个窗口,可以再打开一个窗口
    # root.after(3000, root.quit)#放在这里才能生效 3秒后窗口关闭
    root.title(title)
    #分辨率
    root.geometry('3000x1800')
    var = tk.StringVar()
    label = tk.Label (root,
                      textvariable=var,
                      bg = 'black',
                      fg = 'white',
                      font = ('新宋体',12),
                      anchor="nw",
                      justify='left',
                      width = 2880,
                      height = 1800)
    var.set(content)
    label.pack()
    root.iconbitmap(icon_path)
    root.mainloop()
    # sc.screenshot(img_path)

def show_windows_loop(fwq_pre_txt_address,
                      fwq_pre_img_address,
                      icon_path):
    #获取目录中的文件名
    return_file_list= rf.re_file_name_list(fwq_pre_txt_address)
    print("文件列表:")
    print(return_file_list)
    #2022_06_17 需要使用
    for i in return_file_list:
    #创建ssh窗口 截图 保存截图到img目录
    #2022-06-17
        ssh_txt=fwq_pre_txt_address+i
        print(ssh_txt)
        ssh_title="root@"+i.split('-')[0].replace('.txt','')
        path_pre = fwq_pre_img_address
        image_path = path_pre+i.replace('.txt','')+'.png'
        # doc_image_name=i.replace('.txt','')+'.png'
        # print(ssh_title)
        print('图片的路径:'+image_path)
        print("文件名:"+i)
        # #2022-06-01
        a=show_windows(ssh_txt,ssh_title,icon_path) 
        # b=sc.screenshot(image_path)
        b=sc.screenshot_zone(image_path)
        p1=threading.Thread(target=a,args=(None))
        p2=threading.Thread(target=b,args=(None))
        p2.start()   
        time.sleep(1)
        p1.start()
        # 文档路径  图片路径 图片名

对每个截图进行裁切控制,因为图片要插入到word文档中

#002.屏幕截图的包

import util.screen_catch as sc

# pip install -U pillow 导入库
# 这是screen_catch.py文件
import time
from datetime import datetime
from PIL import ImageGrab  
def screenshot(file_name_png):
    ImageGrab.grab().save(file_name_png)
def screenshot_zone(file_name_png):
    if "96-0.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2095,400)).save(file_name_png)
    if "96-1.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1100,1250)).save(file_name_png)
    if "96-2.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1360,445)).save(file_name_png)
    if "96-3.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1410,1795)).save(file_name_png)    
    if "96-4.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1410,1450)).save(file_name_png)
    if "96-5.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1420,1180)).save(file_name_png)
    if "100-0.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2090,400)).save(file_name_png)
    if "100-1.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1000,1200)).save(file_name_png)
    if "100-2.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1335,500)).save(file_name_png)
    if "100-3.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1440,1795)).save(file_name_png)    
    if "100-4.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1420,1000)).save(file_name_png)
    if "100-5.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1420,1750)).save(file_name_png)
    if "93-0.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2130,500)).save(file_name_png)
    if "93-1.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1000,1100)).save(file_name_png)
    if "93-2.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1345,550)).save(file_name_png)
    if "93-3.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1440,1795)).save(file_name_png)    
    if "93-4.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1440,1200)).save(file_name_png) 
    if "211-0.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2600,500)).save(file_name_png)
    if "211-1.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,970,900)).save(file_name_png)
    if "211-2.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1290,450)).save(file_name_png)
    if "211-3.png" in file_name_png:       
        ImageGrab.grab(bbox=(15,10,1645,1795)).save(file_name_png)
    if "211-4.png" in file_name_png:       
        ImageGrab.grab(bbox=(15,10,1320,1200)).save(file_name_png)    
    if "211-5.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2270,580)).save(file_name_png)   
    if "212-5.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2100,1759)).save(file_name_png) 
    if "212-0.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,2050,500)).save(file_name_png) 
    if "212-1.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,960,900)).save(file_name_png)
    if "212-2.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1300,450)).save(file_name_png)    
    if "212-3.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1440,1795)).save(file_name_png)    
    if "212-4.png" in file_name_png:
        ImageGrab.grab(bbox=(15,10,1440,1150)).save(file_name_png)   
    



# screenshot("D:\\Study\\myproject\\Python_auto_office\\auto_check\\img\\001.png")
# 测试过可以    
# if __name__ == '__main__':
#     screenshot_zone










http://www.kler.cn/a/410239.html

相关文章:

  • UE5肉鸽游戏教程学习
  • 系统设计时应时刻考虑设计模式基础原则
  • RHCSA作业2
  • 【Flutter】搭建Flutter开发环境,安卓开发
  • Linux系统Docker部署开源在线协作笔记Trilium Notes与远程访问详细教程
  • 力扣--LCR 154.复杂链表的复制
  • 制造系统中ERP系统与MES管理系统的区别
  • centos为用户赋予sudo权限
  • 设计模式——简单工厂模型、工厂模式、抽象工厂模式、单例模式、代理模式、模板模式
  • 一台电脑最多支持几个分区
  • 一文详解安全分析方法STPA:以自动紧急制动系统(AEB)为例
  • 一键部署 200+ 开源软件的 Websoft9 面板,Github 2k+ 星星
  • Spring的IOC技术--注解方式
  • 亚信安全与飞书达成深度合作
  • ArcGIS应用指南:ArcGIS制作局部放大地图
  • 大数据架构中的数据存储与管理:从分布式文件系统到NoSQL数据库
  • 重新定义社媒引流:AI社媒引流王如何为品牌赋能?
  • 英语知识网站开发:Spring Boot框架技巧
  • 408数据结构:栈、队列和数组选择题做题笔记
  • Leetcode 每日一题 209.长度最小的子数组
  • 2025 - 科研神器 - 批量处理 PDF、SVG、PNG 和 JPG 文件,将它们转换为彩色 TIFF 文件,并保存到指定的 tiff 文件夹中
  • ARM CCA机密计算安全模型之概述
  • C语言菜鸟入门·关键字·union的用法
  • 【前端】JavaScript作用域与预解析:深入理解问题与解答
  • Python期末复习-系列数据类型
  • 路由缓存后跳转到新路由时,上一路由中的tip信息框不销毁问题解决