接口自动化测试系列-excel管理测试用例

news2024/11/19 21:27:42

代码源码:
框架结构
在这里插入图片描述

核心代码

excel数据处理

from configureUtil.LogUtil import getlog
logger = getlog(targetName='HandleData')
import xlrd
from openpyxl import load_workbook,workbook
from openpyxl.styles import Font, colors
import openpyxl
import os
# from Common.FunctionStart import MoveSpace
# from openpyxl import load_workbook
# from openpyxl.reader.excel import load_workbook
# from openpyxl.styles import Color, Font, Alignment
# from openpyxl.styles import colors
'''
1、cope一份用例所保存的excel,当做执行环境保证测试数据清洁。
2、读取excle数据,返回dick形式的结果。
'''

class ExcelHander():
    '''
    excel操作类,对外提供取excle返回dick结果功能、
    新增excel、sheet、
    cope excel功能、
    写入excel功能等。
    '''
    def __init__(self,filepath):
        self.filepath=filepath
        self.wb=xlrd.open_workbook(filepath)#加载excel
        self.sheet_names=self.wb.sheet_names()#获取excel所有sheet名集合形如:['test', 'test2', 'test3']

    def ExcelDick(self,SheetName):
        '''
        :param SheetName: excel的sheet名字
        :return: 返回读取excel字典类型数据
        '''
        table = self.wb.sheet_by_name(SheetName)
        # 获取总行数
        rowNum = table.nrows
        # 获取总列数
        colNum = table.ncols

        if rowNum<=1:
            logger.error('总行数小于等于1行')
        else:
            logger.debug('开始解析excel----excel总行数:%s'%rowNum)
            # 获取第一行(表头)
            keys = table.row_values(0)
            print(keys)
            r=[]
            j=1
            for i in range(rowNum-1):
                s={}
                # 从第二行开始
                values=table.row_values(j)
                print(values)
                for x in range(colNum):
                    s[keys[x]]=values[x]
                r.append(s)
                j+=1
            # logger.debug('返回列名:%s'%r)
            ExcelDick={}
            ExcelDick[SheetName]=r
            logger.debug('ExcelDick:%s' % ExcelDick)
            return ExcelDick #形如ExcelDick{'sheetName':[{列名:values},{列名:values}]}

    def sheet_method(self,work_book, add_sheet=[]):
        wk = work_book
        # rename default sheet
        ss_sheet = wk["Sheet"]
        # ss_sheet = wk.get_sheet_by_name('Sheet')
        ss_sheet.title = add_sheet[0]
        for i in range(1, len(add_sheet)):
            # add new sheet
            wk.create_sheet(add_sheet[i])
        # switch to active sheet
        # sheet_num = wk.get_sheet_names()
        sheet_num = wk.sheetnames
        last_sheet = len(sheet_num) - 1
        sheet_index = sheet_num.index(sheet_num[last_sheet])
        wk.active = sheet_index

    def CreateExcel(self,filepath,add_sheet=[]):
        '''
        :param filepath: excel地址
        :return: 无
        '''
        # 新建一个工作簿
        p1=os.path.exists(filepath)#判断是否存在
        if p1:
            os.remove(filepath)
        wb2 = workbook.Workbook()
        self.sheet_method(wb2,add_sheet)
        logger.debug('新建excle:%s' % filepath)
        wb2.save(filepath)

    def CopeExcel(self,filepath,newexcelPath,i=0):
        '''
        :param filepath: 原excel地址
        :param newexcelPath: 新excel地址
        :param SheetName: 原sheet的名字
        :return: 无
        '''
        # 读取数据
        logger.debug('读取数据excle:%s' % filepath)
        source = openpyxl.load_workbook(filepath)
        target = openpyxl.load_workbook(newexcelPath)
        sheets1 = source.sheetnames
        sheets2 = target.sheetnames
        logger.info('源sheet列表:%s,目标sheet列表:%s'%(sheets1,sheets2))
        sheet1 = source[sheets1[i]]
        logger.debug('获取sheet:%s' % sheet1)
        sheet2 = target[sheets2[i]]
        table = self.wb.sheet_by_name(sheets1[i])
        # 获取总行数
        max_row = table.nrows
        # 获取总列数
        max_cloumn = table.ncols
        for m in list(range(1, max_row + 1)):
            for n in list(range(97, 97 + max_cloumn)):  # 字母a=97
                n = chr(n)
                i = '%s%d' % (n, m)
                cell1 = sheet1[i].value  # 获取文本数据
                # log.debug('获取文本数据:%s'%cell1)
                sheet2[i].value = cell1
        logger.debug('保存数据')
        target.save(newexcelPath)  # 保存数据
        source.close()
        target.close()

    def WriteExcel(self,filepath,row,cloumn,values,i):
        '''
        :param filepath: excel地址
        :param row: 行号
        :param cloumn: 列号
        :param values: 值
        :param i: sheet的索引
        :return: 无
        '''
        excelpath = load_workbook(filepath)
        sheets = excelpath.sheetnames
        excelpath[sheets[i]].cell(row, cloumn).value = values
        excelpath.save(filepath)
        logger.debug('写数据完成:sheet:%s 行:%s,列:%s,值:%s' % (sheets[i],row, cloumn, values))



def AssembleCase(filepath,newexcelPath):
    '''
    测试用例组装工厂
    :return: 测试用例
    '''
    #新增同名excel、sheet
    test = ExcelHander(filepath)#实例化
    add_sheet = test.sheet_names#获取sheetname列表:['sheet1','sheet2']
    test.CreateExcel(newexcelPath, add_sheet)#创建excel及sheet(cope原excel新建空的execle)
    #给excel填充数据
    for i in range(len(add_sheet)):
        test.CopeExcel( filepath, newexcelPath, i)
    #按sheet分组,组装request数据
    wb = xlrd.open_workbook(newexcelPath)  # 加载新excel
    sheet_names = wb.sheet_names()  # 获取excel所有sheet名集合形如:['sheet1', 'sheet2', 'sheet3']
    caselist=[]
    for i in range(len(sheet_names)):
        caselist.append(test.ExcelDick(sheet_names[i]))#返回所有sheet集合,形如ExcelDick[{'sheetName':[{列名:values},{列名:values}]},{'sheetName':[{列名:values},None]
    #接口请求数据
    return caselist

def wordFormat(filepath,postition,size,name,bold,italic,i=0):
    '''
    格式化表格数据
    postition,位置如A1
    size,字体大小
    name,字体类型名
    color,字体颜色
    bold,是否加粗
    italic,是否斜体
    i,sheet索引
    :param filepath:指定excle
    :return:
    '''
    #激活excle
    wb = openpyxl.load_workbook(filepath)
    sheet1 = wb.worksheets[i]
    italic24Font = Font(size=size, name=name, bold=bold ,italic=italic)
    sheet1[postition].font = italic24Font
    wb.save(filepath)

def backFormat(filepath,n,m,fgColor,i=0):
    '''
    :param n: 行号
    :param m: 列号
    :param fgColor: 颜色 # blue 23ff00 greet 6e6fff  red ff0f06
    :param i: sheet索引
    :return:
    '''
    import openpyxl.styles as sty
    wb = openpyxl.load_workbook(filepath)
    sheet1 = wb.worksheets[i]
    sheet1.cell(row=n, column=m).fill = sty.fills.PatternFill(fill_type='solid',fgColor=fgColor)
    wb.save(filepath)

def excleFormat(filepath):
    '''
    filepath 格式化excle
    :return:
    excel表头宋体斜体加粗背景色blue 12号 6e6fff
    其他内容宋体背景色无 11号 ffffff
    成功的 宋体背景色绿色 11号 23ff00
    失败 宋体背景色绿色 11号 ff0f06
    '''
    wb = xlrd.open_workbook(filepath)#加载
    sheet_names = wb.sheet_names()  # 获取excel所有sheet名集合形如:['test', 'test2', 'test3']
    #######字体
    if sheet_names==[]:
        logger.debug('excel是空sheet')
        pass
    else:
        for i,SheetName in enumerate(sheet_names)  :
            table = wb.sheet_by_name(SheetName)
            # logger.debug('获取第%s个sheet=%s'%(i,SheetName))
        # 获取总行数
            rowNum = table.nrows
            # logger.debug('行数:%s'%(rowNum))
        # 获取总列数
            colNum = table.ncols
            # logger.debug('列数:%s' % (colNum))
            name='Times New Roman'
            if rowNum<1:
                # logger.debug('空sheet')
                pass
            else:
                for m in list(range(1, rowNum + 1)):
                    for n in list(range(97, 97 + colNum)):  # 字母a=97
                        if m==1:
                            n = chr(n)
                            postition = '%s%d' % (n, m)
                            color='6e6fff'
                            bold=True
                            italic=True
                            size=12
                            # logger.debug('格式第一行数据')
                            wordFormat(filepath, postition, size, name, bold, italic, i)
                            fgColor='6e6fff'
                            backFormat(filepath,m, ord(n)-96, fgColor, i)
                        else:
                            n = chr(n)
                            postition = '%s%d' % (n, m)
                            color = '6e6fff'
                            bold = False
                            italic = False
                            size = 11
                            # logger.debug('格式化%s行数据'%(m))
                            wordFormat(filepath, postition, size, name, bold, italic, i)
                            cell_value = table.cell_value(m-1,10)
                            if cell_value=='TRUE'or cell_value==1 :
                                fgColor='23ff00'
                                # logger.debug('获取到结果:TRUE')
                                backFormat(filepath,m, 11, fgColor, i)
                            elif cell_value=='FLASE' or cell_value==0:
                                fgColor = 'ff0f06'
                                # logger.debug('获取到结果:FLASE')
                                backFormat(filepath,m, 11, fgColor, i)
                            else:
                                logger.error('行号:%s ' % (m - 1))
                                # logger.error('没有获取到结果:%s'%cell_value)

########背景色


if __name__=='__main__':
    filepath = r'E:\plant\AutoUniversalInterface\Common\TestCase\demo.xlsx'
    newexcelPath=r'E:\plant\AutoUniversalInterface\Common\TestResult\demo.xlsx'
    # 打开excel
    postition='A1'
    size=14#大小
    name='Times New Roman'#字体
    color=colors.BLACK#字体颜色
    bold = False #是否加粗
    italic = True #是否斜体
    # headerFormat(filepath, postition,size, name, color,bold,italic)
    # wordFormat(filepath, postition, size, name, bold, italic, i=0)
    # fgColor = '23ff00'
    # n=2
    # m=11
    # backFormat(filepath,n, m, fgColor, i=0)
    # wb = xlrd.open_workbook(filepath)
    # table = wb.sheet_by_name('test')
    #
    # cell_value = table.cell_value(1, 10)
    # print(cell_value)
    excleFormat(newexcelPath)


requests请求封装

import requests
# 禁用安全请求警告
import urllib3
urllib3.disable_warnings()
import json

def callInterface(session,url, param=None,parammode='data', method='post', headers=None,verify=False,  jsonResponse=True):
    """
    封装的http请求方法,接受session url, param, method, verify, headers 发起http请求并返回接口返回的json
    :param session: requests session 对象
    :param url: 请求地址
    :param param: 请求参数
    :param parammode:请求参数传入方式 data/json
    :param method: 请求方式 默认post
    :param verify: ssl检验 默认关
    :param headers: http headers
    :param jsonResponse: 是否json格式response标志
    :return: 接口返回内容/None
    """
    logger.debug(f'开始调用接口:{url},参数为:{param}')
    res = None
    returnJson = None
    if method == 'POST':
        logger.debug(f'请求方法为:%s'%method)
        if parammode=='data':
            logger.debug(f'请求参数类型为:%s' % parammode)
            res = session.post(url, data=param, verify=verify, headers=headers)
        elif parammode=='json':
            logger.debug(f'请求参数类型为:%s' % parammode)
            res = session.post(url, json=param, verify=verify, headers=headers)
    elif method == 'GET':
        logger.debug(f'请求方法为:%s' % method)
        res = session.get(url, params=param, verify=verify, headers=headers)
    try:
        if res.status_code == 200:
            logger.debug(f'接口响应码:200')
            if jsonResponse:
                try:
                    returnJson = res.json()
                except (TypeError, json.JSONDecodeError) as e:
                    logger.error(f'请求接口:{url}出错,返回:{res.text}')
                    logger.error(e)
                    return {'fail':str(e)}
            else:
                try:
                    returnJson = {'returnText': res.text[:1000]}
                except Exception as e:
                    logger.error('请求接口出错')
                    logger.error(e)
                    return {}
        else:
            logger.error('请求接口失败!响应码非200!')
        logger.debug(f'接口调用完成 返回:{returnJson}')
        return returnJson
    except Exception as e:
        return {'fail':str(e)}

检查点函数

"""
检查中心
1、检查结果是否包含于预期结果
2、结果的sql执行结果是否等于预期
3、没有检查条件走默认检查
"""
from configureUtil.LogUtil import getlog
logger = getlog(targetName='CheckPoint')
from configureUtil.DataManangerl import DBmananger

#判断dict1的key是否存在dict2中
def KeyExist(dict1,dict2):
    n = 0
    if dict1=={}:
        return False
    for key in dict1.keys():
        if key in dict2.keys():
            pass
            n=n+1
            if n==len(dict1):
                return True
        else:
            return False

#判断dict2是否包含dict1
def Compare_ListDict(dick1, dick2):
    flag = False
    n = 0
    keyexist=KeyExist(dick1, dick2)
    if keyexist ==True:
        for i in dick1.keys():
            n=n+1
            if dick1[i] != dick2[i]:
                break
            elif n==len(dick1):
                flag = True
    elif dick1=={}:
        flag = True
    else:
        pass
    return flag

"""判断sql结果是否为()"""

def JudgeSqlEmpty(sql,env):
    '''
    :param sql: 需要执行sql
    :param env: 执行环境
    :return: 执行结果:true或者false
    '''
    try:
        result=DBmananger(env).callMysql(sql)
        logger.debug(result)
    except Exception as e:
        logger.error(e)
        result=()
    if result==():
        return False
    else:
        return True

数据处理工厂

# 预置条件、用例依赖处理中心:
# 1、用例依赖标志
# 2、数据处理:支持sql增删改查操作
from configureUtil.LogUtil import getlog
from Common.FunctionStart import MoveSpace
logger = getlog(targetName='Precondition')
def DataSplit(SplitSign=';',StringOne=''):

    if isinstance(StringOne,str):
        result=StringOne.split(SplitSign,-1)
    else:
        result=[]
    result=list(filter(None, result))#去掉列表空字符及None
    return result

def todict(func,SplitSign=';',StringOne=''):
    '''
       数据分离器
       :param StringOne: string类型入参
       :param SplitSign: 分离标志:如以冒号分离,则传入":"
       :return: 分离list结果:{[{'SQL':[,]}],['$':[,]]}
       '''
    MoveSpace(StringOne)
    SplitSign = ';'
    SplitSign1 = (func(SplitSign,StringOne))
    # print(SplitSign1)
    dict = {}
    list1 = []
    list2 = []
    list3 = []
    # print(SplitSign1)
    import re
    # keys=re.findall(r'SQL:',StringOne,re.I)+re.findall(r'(\$[a-z]+):',StringOne,re.I)
    for i in SplitSign1:
        values = i.split(':')
        list1.append(MoveSpace(values[-1]))  # values
        list2.append(MoveSpace(values[0]))  # keys
        if MoveSpace(values[0]) in dict.keys():
            for i in dict[MoveSpace(values[0])]:
                list3.append(i)
            list3.append(MoveSpace(values[-1]))
            dict[MoveSpace(values[0])] = list3
        else:
            list4=[]
            list4.append(MoveSpace(values[-1]))
            dict[MoveSpace(values[0])] = list4
    return dict

发送邮件函数

import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import encoders
from email.mime.base import MIMEBase
from email.utils import parseaddr, formataddr
from configureUtil.DataFile import mailenv

# 格式化邮件地址
def formatAddr(s):
    name, addr = parseaddr(s)
    return formataddr((Header(name, 'utf-8').encode(), addr))
def sendMail(body, attachment,title='接口自动化测试报告'):
    # smtp_server = 'smtp.163.com'
    smtp_server = 'mail.suishouji.com'
    smtp_server = mailenv['smtp_server']
    from_mail = mailenv['from_mail']
    mail_pass =mailenv['smtp_server']
    mail_passwd=mailenv['mail_passwd']
    to_mail = mailenv['to_mail']
    cc_mail = mailenv['cc_mail']
    # 构造一个MIMEMultipart对象代表邮件本身
    msg = MIMEMultipart()
    # msg = MIMEText('hello, send by Python...', 'plain', 'utf-8')
    # Header对中文进行转码
    msg['From'] = formatAddr('<%s>' % (from_mail))
    msg['To'] = formatAddr('<%s>' % (to_mail))
    msg['Cc'] = formatAddr('<%s>' % (cc_mail))
    msg['Subject'] = Header('%s'% title).encode()
    # to_mail = to_mail.split(',')
    # cc_mail= cc_mail.split(',')
    to_mail.extend(cc_mail)
    # plain代表纯文本
    msg.attach(MIMEText(body, 'plain', 'utf-8'))
    # 二进制方式模式文件
    for i in range(len(attachment)):
        with open(attachment[i], 'rb') as f:
            # MIMEBase表示附件的对象
            mime = MIMEBase('text', 'txt', filename=attachment[i])
            # filename是显示附件名字,加上必要的头信息:
            mime.add_header('Content-Disposition', 'attachment', filename=attachment[i])
            mime.add_header('Content-ID', '<0>')
            mime.add_header('X-Attachment-Id', '0')
            # 获取附件内容
            mime.set_payload(f.read())
            # 用Base64编码:
            encoders.encode_base64(mime)
            # 作为附件添加到邮件
            msg.attach(mime)
            # msg.attach(MIMEText(html, 'html', 'utf-8'))
    try:
        server = smtplib.SMTP(smtp_server, "25")
        server.set_debuglevel(1)
        server.login(from_mail, mail_passwd)
        server.sendmail(from_mail,to_mail,msg.as_string())  # as_string()把MIMEText对象变成str
        logger.info ("邮件发送成功!")
        server.quit()
    except smtplib.SMTPException as e:
        logger.error ("Error: %s" % e)

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

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

相关文章

Docker-基础命令使用

文章目录 前言命令帮助命令执行示意图docker rundocker psdocker inspectdocker execdocker attachdocker stopdocker startdocker topdocker rmdocker prune参考说明 前言 本文主要介绍Docker基础命令的使用方法。 命令帮助 Docker命令获取帮助方法 # docker -h Flag shor…

网易低代码引擎Tango正式开源

一、Tango简介 Tango 是一个用于快速构建低代码平台的低代码设计器框架,借助 Tango 只需要数行代码就可以完成一个基本的低代码平台前端系统的搭建。Tango 低代码设计器直接读取前端项目的源代码,并以源代码为中心,执行和渲染前端视图,并为用户提供低代码可视化搭建能力,…

【vue2第十二章】ref和$refs获取dom元素 和 vue异步更新与$nextTick使用

ref和$refs获取dom元素 为什么会有 ref 和 $refs&#xff1f; 因为在vue页面中使用dom查找元素&#xff0c;不管你是不是在子组件里面查找&#xff0c;查找的都是整个页面的元素&#xff0c;如果你想查找单独组件里面的元素是不容易实现的&#xff0c;除非把每个组件的class写…

亚马逊云科技通过生成式AI,帮助清华RIOS加速计算和分析的处理效率

近日&#xff0c;硬件创建平台Efabless宣布了其第一届“生成式AI开源芯片设计挑战赛”&#xff08;AI Generated Open-Source Silicon Design Challenge&#xff09;的评选结果。来自清华大学的RISC-V国际开源实验室&#xff08;RIOS Lab&#xff09;团队基于亚马逊云科技云上科…

npm install依赖冲突解决办法

今天npm的时候发现报错&#xff0c;原来是依赖冲突了 npm后面加上这个指令就可以顺利的安装依赖了。问题主因就是不同开发用了不同版本node导致依赖版本不同&#xff0c;出现了成功冲突&#xff0c;这是段指令&#xff1b;它告诉npm忽略项目中引入的各个依赖模块之间依赖相同但…

桌面平台层安全随手记录

声明 本文是学习桌面云安全技术要求. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 桌面平台层安全 桌面接入安全 用户标识 一般要求 本项要求包括&#xff1a; a) 系统应为用户提供唯一的身份标识&#xff0c;同时将用户的身份标识与该用户的所…

FPGA/IC秋招面试题 1(解析版)

分享个人觉得遇到还不错的题&#xff0c;后续有会继续补充。。。 以下题目均来自网络平台&#xff0c;用于学习交流如有侵权立马删除!!! 1. Verilog语言中&#xff0c;下面哪些语句不可被综合() A. #delay语句 B. initial语句 C. always语句 D. 用gen…

软件测试师之数的表示

目录 一、数的进制(1)十进制&#xff1a;D(2)二进制&#xff1a;B(3)十六进制&#xff1a;H(4)八进制&#xff1a;O/Q 二、其他进制转十进制(1)二进制转十进制(2)十六进制转十进制(3)八进制转十进制 三、二进制与十六进制/八进制进行转换四、考法 一、数的进制 (1)十进制&…

怎么把pdf转换成高清图片?

怎么把pdf转换成高清图片&#xff1f;最近&#xff0c;我的同事遇到了一个问题&#xff0c;现在她需要将一些pdf文件转换成高清的图片&#xff0c;这件事情让让她感到非常无助&#xff0c;因为她非常着急需要将这些文件转换为图片格式&#xff0c;以便更好的在今后的工作中进行…

AJAX学习笔记5同步与异步理解

AJAX学习笔记4解决乱码问题_biubiubiu0706的博客-CSDN博客 示例 前端代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>演示AJAX同步和异步</title> </head> <body> <script…

5个强大的Java分布式缓存框架推荐

在开发中大型Java软件项目时&#xff0c;很多Java架构师都会遇到数据库读写瓶颈&#xff0c;如果你在系统架构时并没有将缓存策略考虑进去&#xff0c;或者并没有选择更优的缓存策略&#xff0c;那么到时候重构起来将会是一个噩梦。 在开发中大型Java软件项目时&#xff0c;很…

【LeetCode-面试经典150题-day21】

目录 120.三角形最小路径和 64.最小路径和 63.不同路径Ⅱ 5.最长回文子串 120.三角形最小路径和 题意&#xff1a; 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标 与 上一层结点下标…

【项目 计网10】4.28 poll API介绍及代码编写

文章目录 4.28 poll API介绍及代码编写代码实现 4.28 poll API介绍及代码编写 #include <poll.h> struct pollfd{int fd;//委托内核检测的文件描述符short events;//委托内核检测文件描述符的什么事件short revents;//文件描述符实际发生的事件 }; int poll(struct poll…

【ARM CoreLink CCI-400 控制器简介】

文章目录 CCI-400 介绍 CCI-400 介绍 CCI&#xff08;Cache Coherent Interconnect&#xff09;是ARM 中 的Cache一致性控制器。 CCI-400 将 Interconnect 和coherency 功能结合到一个模块中。它支持多达两个ACE master 点的interface&#xff0c;例如&#xff1a; Cortex-A…

Verilog零基础入门(边看边练与测试仿真)-笔记

文章目录 第一讲第二讲第三讲第四讲 第一讲 1、testbench 没有端口&#xff0c;所以没括号 2、testbench 输入端 之后要变动 所以定义为reg 3、#10 &#xff1a;过10个时间单位 &#xff1b;’timescale 1ns/10ps 即 1ns 的时间单位 10ps的时间精度 4、reg 型变量赋值的时候 用…

若依新建模块

下面介绍如何在若依框架下新建一个子模块 第一步&#xff1a; 如图操作&#xff1a; 1. 2. 3. 4.在刚建立的子模块的pom.xml文件添加通用工具依赖 代码&#xff1a; <dependencies> <!-- 导入通用工具--><dependency><groupId>com.rchuing&l…

C语言文本为什么不包括库函数和预处理命令

C语言的文本不包括库函数和预处理命令 是因为库函数和预处理命令并不是C语言本身的一部分&#xff0c; 它们是由C语言标准库和预处理器提供的功能。 C语言标准库是一组预定义的函数和常量&#xff0c; 用于提供常见的功能&#xff0c;如输入输出、字符串处理、数学计算等。 …

【深入解析spring cloud gateway】06 gateway源码简要分析

上一节做了一个很简单的示例&#xff0c;微服务通过注册到eureka上&#xff0c;然后网关通过服务发现访问到对应的微服务。本节将简单地对整个gateway请求转发过程做一个简单的分析。 一、核心流程 主要流程&#xff1a; Gateway Client向 Spring Cloud Gateway 发送请求请求…

普通用户使用spark的client无法更新Ranger策略

普通用户使用spark的client无法更新Ranger策略 报错图片&#xff1a; WARN org.apache.ranger.admin.client.RangerAdminRESTClient: Error getting Roles. secureModetrue, usercaojianxiangUCDIPA.VIATRIS.CC (auth:KERBEROS)&#xff0c;responsef"httpStatusCode&quo…

ToBeWritten之基于ATTCK的模拟攻击:闭环的防御与安全运营

也许每个人出生的时候都以为这世界都是为他一个人而存在的&#xff0c;当他发现自己错的时候&#xff0c;他便开始长大 少走了弯路&#xff0c;也就错过了风景&#xff0c;无论如何&#xff0c;感谢经历 转移发布平台通知&#xff1a;将不再在CSDN博客发布新文章&#xff0c;敬…