【Python搞定车载自动化测试】——Python基于Pytest框架实现UDS诊断自动化(含Python源码)

系列文章目录

【Python搞定车载自动化测试】系列文章目录汇总

文章目录

  • 系列文章目录
  • 💯💯💯 前言💯💯💯
    • 一、环境搭建
      • 1.软件环境
      • 2.硬件环境
    • 二、目录结构
    • 三、源码展示
      • 1.诊断基础函数方法
      • 2.诊断业务函数方法
      • 3.27服务安全解锁
      • 4.自动测试用例
      • 5.配置参数
    • 四、日志和报告
      • 1.测试日志
      • 2.测试报告
    • 五、完整源码链接


💯💯💯 前言💯💯💯

在之前的专栏【如何学习CAN总线测试】中介绍了如何通过CAPL语言实现UDS诊断测试,但CAPL语言依赖于Vector CANoe设备,随着智能电动汽车行业的发展,目前使用Python语言实现自动化测试的需求越来越广,本章节主要介绍如何使用Python语言基于Pytest自动化框架来实现UDS诊断自动化测试。
首先回顾一下UDS诊断基础知识:

统一诊断服务(Unified Diagnostic Services),简称UDS。是ISO 15765和ISO 14229定义的一种汽车通用诊断协议,位于OSI模型中的应用层,它可在不同的汽车总线(例如CAN、LIN、Flexray、Internet、K-line)上实现,是当前汽车领域广泛使用的一种车载诊断协议标准。


UDS协议的应用层定义是ISO 14229-1,目前大部分汽车厂商均采用UDS on CAN的诊断协议。
根据UDS的诊断协议,汽车上的控制系统需要根据规则化的诊断协议进行故障记录和处理,最终体现为诊断故障代码(Diagnostic Trouble Code,DTC)的方式。例如,网络通信丢失的故障诊断机制:
自动变速箱控制单元(Transmission Control Unit,TCU)和制动防抱死系统(Antilock Brake System,ABS)是CAN车载网络上的两大电子控制单元,这2个ECU要通过CAN网络进行大量的信息交互。但是由于电磁干扰、串扰、静电等外界干扰或电子控制单元本身控制策略引起的通信停止等原因,2个电子控制单元之间可能会出现通信丢失的现象。
控制系统需要将故障信息(例如:通信丢失故障信息)诊断出来,以处理通信被破坏时出现丢失帧的故障现象,并记录为DTC。一旦某一控制系统,如TCU监测到一段规定的时间内并没有接收到ABS发来的通信数据,便将此DTC记录下来。外部诊断设备通过规则的诊断通信与控制系统建立诊断通信连接,并选择相应的诊断方式。例如:读取故障信息服务时,就会将此故障信息读出,并在诊断仪中显示出来。


UDS诊断服务共分为六大单元:
1、诊断和通信管理功能单元(Diagnostic and Communication Management)
$10 - 诊断会话控制(DiagnosticSessionControl)
$11 - 电控单元复位(ECUReset)
$27 - 安全访问(SecurityAccess)
$28 - 通讯控制(CommunicationControl)
$3E - 待机握手(TesterPresent)
$83 - 访问时间参数(AccessTimingParameter)
$84 - 安全数据传输(SecuredDataTransmission)
$85 - 诊断故障码设置控制(ControlDTCSetting)
$86 - 事件响应(ResponseOnEvent)
$87 - 链路控制(LinkControl)
2、数据传输功能单元(Data Transmission)
$22 - 通过ID读数据(ReadDataByldentifier)
$23 - 通过地址读内存(ReadMemoryByAddress)
$24 - 通过ID读比例数据(ReadScalingDataByidentifier)
$2A - 通过周期ID读取数据(ReadDataUyPeriodicidentifier)
$2C - 动态定义标识符(DynamicallyDefineDataldentifier)
$2E - 通过ID写数据(WriteDataByldentifier)
$3D - 通过地址写内存(WriteMemoryByAddress)
3、存储数据传输功能单元(Stored Data Transmission)
$14 - 清除诊断信息(ClearDiagnosticInformation)
$19 - 读取故障码信息(ReadDTCInformation)
4、输入输出控制功能单元(Input & Output Control)
$2F - 通过标识符控制输入输出(InputOutputControlByIdentifier)
5、例行程序功能单元(Remote Activation of Routine)
$31 - 例行程序控制(RoutineControl)
6 、传下载功能单元(Upload & Download)
$34 - 请求下载(RequestDownload)
$35 - 请求上传(RequestUpload)
$36 - 数据传输(TransferData)
$37 - 请求退出传输(RequestTransferExit)
$38 - 请求文件传输(RequestFileTransfer)


一、环境搭建

1.软件环境

Python版本:python3.9
第三方库:
pip install allure-pytest2.13.5
pip install can-isotp
2.0.4
pip install python-can4.3.1
pip install udsoncan
1.23.0
allure:安装allure工具并设置环境变量,https://github.com/allure-framework/allure2/releases

2.硬件环境

支持CAN设备硬件接口:
在这里插入图片描述
https://python-can.readthedocs.io/en/stable/configuration.html


二、目录结构

在这里插入图片描述
dll目录:存放27服务安全解锁DLL文件(同CANoe中使用的DLL文件)。
public_method目录:存放公共函数方法和27安全解锁工具。
test_case目录:存放python自动化测试用例。
update目录:存放升级包和效验文件。
config.py文件:CAN相关配置参数。
run.py文件:运行入口文件。


三、源码展示

1.诊断基础函数方法

base_can.py文件主要封装了CAN初始化、诊断配置、诊断请求、诊断响应基础方法,源码如下:

class CanBus:def __init__(self, interface: str = None, channel: int = None, bitrate: int = None, fd: bool = None,data_bitrate: int = None, can_filters: CanFilters = None, *args, **kwargs):self.interface = interfaceself.channel = channelself.bitrate = bitrateself.fd = fdself.data_bitrate = data_bitrateself.can_filters = can_filterstry:self.bus = can.interface.Bus(channel=self.channel, interface=self.interface, app_name="CANoe",bitrate=self.bitrate, fd=self.fd, data_bitrate=self.data_bitrate,can_filters=self.can_filters, *args, **kwargs)except Exception as e:raise Exception("初始化失败:%s" % e)else:print("初始化成功")def diag_congfig(self, tx: int, rx: int, addressingmode=isotp.AddressingMode.Normal_11bits):"""诊断配置函数:param tx: 诊断请求ID,功能寻址、物理寻址:param rx: 诊断响应ID:return:"""self.isotp_params = {'stmin': 20,  # 流控帧间隔时间'blocksize': 8,  # 流控帧单包大小,0表示不限制'tx_padding': 0,  # 当 notNone表示用于填充发送的消息的字节。'rx_flowcontrol_timeout': 1000,  # 在停止接收和触发之前等待流控制帧的毫秒数'rx_consecutive_frame_timeout': 1000,  # 在停止接收和触发 a 之前等待连续帧的毫秒数}try:self.tp_addr = isotp.Address(addressing_mode=addressingmode, txid=tx, rxid=rx)  # 网络层寻址方案tp_stack = isotp.CanStack(bus=self.bus, address=self.tp_addr, params=self.isotp_params)  # 网络/传输层(IsoTP 协议)self.conn = PythonIsoTpConnection(tp_stack)  # 应用层和传输层之间的接口except Exception as e:print("UDS配置失败:%s" % e)return self.conndef diag_request(self, request_command: str, request_data_log_flag=True):"""诊断请求"""requestPdu = binascii.a2b_hex(request_command.replace(' ', ''))if not self.conn.is_open():self.conn.open()try:self.conn.send(requestPdu)except Exception as e:print("诊断请求失败:%s" % e)else:req_info = ''request_command = request_command.replace(' ', '')for i in range(len(request_command)):if i >= len(request_command) / 2:breakreq_info += request_command[2 * i:2 * i + 2] + ' 'if request_data_log_flag:print("诊断请求:%s" % req_info)def diag_respond(self, timeout1=1):"""诊断响应"""try:respPdu = self.conn.wait_frame(timeout=timeout1)except Exception as e:print(e)else:if respPdu is None:return Noneresp1 = respPdu.hex().upper()resp2 = ''for i in range(len(resp1)):if i != 0 and i % 2 == 0:resp2 += ' 'resp2 += resp1[i]print("诊断响应:%s" % resp2)return resp2

2.诊断业务函数方法

fun_can.py主要二次封装UDS诊断函数,包括:27安全解锁,34服务、36服务、诊断78响应处理、UDS诊断测试、CRC效验等函数,源码如下:

import binascii
import os
import subprocess
import timeimport pytestfrom config import Parameter
from public_method.base_can import CanBusclass CanMethod(CanBus):def __init__(self, config):self.interface = config['can']['interface']self.channel = config['can']['channel']self.bitrate = config['can']['bitrate']self.fd = config['can']['canfd']self.data_bitrate = config['can']['data_bitrate']self.addressingmode = config['can']['addressing_mode']self.tx = config['can']['physics_id_default']self.rx = config['can']['response_id_default']CanBus.__init__(self, interface=self.interface, channel=self.channel, bitrate=self.bitrate, fd=self.fd,data_bitrate=self.data_bitrate, )self.diag_congfig(addressingmode=self.addressingmode, tx=self.tx, rx=self.rx)self.sign_nrc78 = 0def __diag_get_seed(self, req_data="27 01"):"""27服务获取种子并解析"""self.diag_request(req_data)try:uds_res_data = self.conn.specific_wait_frame(timeout=2)while uds_res_data[0] == 0x7F and uds_res_data[2] == 0x78:print("已收到 %d bytes : [%s]" % (len(uds_res_data), binascii.hexlify(uds_res_data)))uds_res_data = self.conn.specific_wait_frame(timeout=3)resp1 = uds_res_data.hex().upper()resp2 = ''for i in range(len(resp1)):if i != 0 and i % 2 == 0:resp2 += ' 'resp2 += resp1[i]print("诊断响应:%s" % resp2)except:print("响应数据失败")else:seed = []res_seed = resp2.split(' ')[2:]for i in range(len(res_seed)):seed.append(eval('0x' + res_seed[i]))print("seed:%s" % seed)return seeddef get_key_level(self, seed):"""dll_security_unlock.exe工具解锁语法:dll_security_unlock.exe --dll_path dome.dll --seed [11,22,33,44] --seedsize 4 --level 1 --keysize 4--dll_path DLL路径--seed 请求种子--seedsize 种子长度--level 安全级别--keysize 秘钥长度"""seed = str(seed).replace(' ', '')tool = os.path.join(os.path.dirname(__file__), 'dll_security_unlock.exe')cmd = '{} --dll_path {} --seed {}'.format(tool, os.path.join(os.path.dirname(os.path.dirname(__file__)), r'dll\dome.dll'), seed)key = subprocess.getoutput(cmd)return keydef unlock_level(self):"""27安全解锁"""seed = self.__diag_get_seed(req_data="27 01")if seed is not None:if seed != 0 and len(seed) > 1:key = self.get_key_level(seed)print("key= %s" % key)req_data = "27 02 %s" % keyself.diag_request(req_data)self.uds_respond_0x78()time.sleep(0.1)else:print("seed响应不正确")def diag_send(self, req_data="3E 80"):"""发送诊断请求,不断言诊断响应"""self.diag_request(req_data)response = self.uds_respond_0x78()time.sleep(0.1)return responsedef diag_send_exp(self, req_data="3E 80", exp=None):"""发送诊断请求,并断言诊断响应"""self.diag_request(req_data)result = self.__diag_test_response_judge(exp=exp)time.sleep(0.1)return resultdef diag_send_0x34(self, req_data="34 00 44", address="00 00 00 00", size=0, exp=None):"""刷写时使用,请求传输升级包"""print("传输包大小= %s" % size)self.diag_request(req_data + address + "{:08X}".format(size))self.__diag_test_response_judge(exp=exp)time.sleep(0.1)def diag_send_0x36(self, req_data="36", trans_size=255, path="", exp=None):"""36服务传包"""total_size = os.path.getsize(path)print("size = %s" % total_size)with open(path, "rb") as f:file_read = f.read()print("CRC= %s" % "{:02X}".format(binascii.crc32(file_read)))file_byte = []for i in range(len(file_read)):file_byte.append("{:02X}".format(file_read[i]))sequence = 1transmitted_size = 0try:status = Truewhile status:trans_data = ""for i in range(trans_size):if transmitted_size < total_size:trans_data = trans_data + file_byte[transmitted_size]transmitted_size = transmitted_size + 1else:status = Falsebreakprint("data_num=%s" % transmitted_size)self.diag_request(request_command=req_data + "{:02X}".format(sequence) + trans_data,request_data_log_flag=False,)print(req_data + "{:02X}".format(sequence) + "...")self.__diag_test_response_judge(exp=exp)sequence += 1if sequence == 256:sequence = 0finally:print("36传输结束")def diag_crc32(self, req_data="31 01 02 02", path="", exp=None):"""刷写时使用,CRC32校验"""size = os.path.getsize(path)print("size = %s" % size)with open(path, "rb") as f:file_read = f.read()crc32 = "{:08X}".format(binascii.crc32(file_read))print("crc 32 = %s " % crc32)self.diag_send_exp(req_data=req_data + crc32, exp=exp)def __diag_session_mode(self, session):"""诊断会话模式"""if session == "01":self.diag_send(req_data="10 01")elif session == "03":self.diag_send(req_data="10 03")elif session == "02":self.diag_send(req_data="10 03")self.unlock_level()self.diag_send(req_data="10 02")def uds_respond_0x78(self, timeout1=2):"""78响应处理"""response = self.diag_respond(timeout1=timeout1)if response is not None:try:response2 = response.replace(' ', '')cyc = 0while response2[:2] == '7F' and response2[4:6] == '78':self.sign_nrc78 = 1response = self.diag_respond(timeout1=timeout1)if response is not None:response2 = response.replace(' ', '')cyc += 1if cyc > 20:breakexcept Exception as e:print("异常:%s" % e)return responsedef __diag_test_response_judge(self, exp=None):"""断言响应结果与预期结果是否一致"""response = self.uds_respond_0x78()response_return = responseif (exp is not None) & (response is not None):exp = exp.replace(" ", "").upper()exp2 = ""for i in range(len(exp)):if i != 0 and i % 2 == 0:exp2 += " "exp2 += exp[i]exp = exp2if len(exp) < len(response):response = response[0: len(exp)]if response == exp:return response_returnelse:print("诊断结果与预期结果不匹配")pytest.fail("诊断结果与预期结果不匹配")def diag_test(self, session="01", req_data=None, exp=None):"""诊断测试:param session: 执行前会话模式,01默认会话,02编程会话,03扩展会话:param req_data:请求数据:param exp:预期结果:return:"""self.__diag_session_mode(session=session)if req_data is not None:self.diag_request(req_data)self.__diag_test_response_judge(exp=exp)uds = CanMethod(Parameter.config)

3.27服务安全解锁

dll_security_unlock.exe文件可实现DLL安全解锁,使用方法如下:
语法:
举例:dll_security_unlock.exe --dll_path dome.dll --seed [11,22,33,44] --seedsize 4 --level 1 --keysize 4
–dll_path DLL路径
–seed 请求种子
–seedsize 种子长度
–level 安全级别
–keysize 秘钥长度

4.自动测试用例

test_uds.py主要是自动化测试用例举例,包括10服务测试、11服务测试、14服务测试、19服务测试、22服务测试、28服务测试、31服务测试、85服务测试等,源码如下:

import allurefrom public_method.fun_can import udsclass TestDiag:@allure.title("诊断测试10服务")def test_diag_0x10(self):print("#####诊断测试10服务#####")uds.diag_test(session="", req_data="10 01", exp="50 01")@allure.title("诊断测试11服务")def test_diag_0x11(self):print("#####诊断测试11服务#####")uds.diag_test(session="", req_data="11 01", exp="51 01")@allure.title("诊断测试14服务")def test_diag_0x14(self):print("#####诊断测试14服务#####")uds.diag_test(session="03", req_data="14 C0 00 00", exp="54 C0")@allure.title("诊断测试19服务")def test_diag_0x19(self):print("#####诊断测试59服务#####")uds.diag_test(session="", req_data="19 01 09", exp="59 01 09")@allure.title("诊断测试22服务")def test_diag_0x22(self):print("#####诊断测试22服务#####")uds.diag_test(session="03", req_data="22 60 D7", exp="62 60 D7")@allure.title("诊断测试28服务")def test_diag_0x28(self):print("#####诊断测试28服务#####")uds.diag_test(session="03", req_data="28 03 01", exp="68 03")@allure.title("诊断测试31服务")def test_diag_0x31(self):print("#####诊断测试31服务#####")uds.diag_test(session="03", req_data="31 01 E0 F5", exp="71 01 E0 F5")@allure.title("诊断测试85服务")def test_diag_0x85(self):print("#####诊断测试85服务#####")uds.diag_test(session="03", req_data="85 01", exp="C5 01")

5.配置参数

config主要配置CAN和诊断相关的参数:
interface:配置can设备类型(支持python-can三方库的设备)
channel:通道
bitrate:波特率
addressing_mode:数据比特率
physics_id_default:物理寻址
response_id_default:响应寻址

class Parameter():"""CAN参数配置"""config = {"can": {"interface": "vector","channel": 0,"bitrate": 500000,"data_bitrate": 2000000,"canfd": False,  # 是否canfd"addressing_mode": 0,"physics_id_default": 0x56A,"response_id_default": 0x56B,"function_id_default": 0x56C,}}

四、日志和报告

1.测试日志

)

2.测试报告

在这里插入图片描述

五、完整源码链接

如下载源码链接失效,请将购买专栏截图和用户名截图通过CSDN私信发送给博主,博主更新源码链接:
链接:https://pan.baidu.com/s/1EIx0upnVz-ZiudXE9Ki8Bg
提取码:4kdj

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

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

相关文章

深入探索Python基础:两个至关重要的函数

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、初学者的基石&#xff1a;print与input函数 二、类型转换&#xff1a;从字符串到浮点数…

第十四节:带你梳理Vue2:filters过滤器

过滤器是什么? 过滤器是一种在模板中处理数据的便捷方式, 会经常在其他模板语言中见到, 他们特别适合对字符串和数字进行简单的显示变化. 1. 通过案例理解过滤器 示例: 对于数字价格处理 1.1 Mastache语法中处理价格数字 <div id"app"><!-- 正常处理 -…

【完整解析】2024电工杯数学建模A题论文与代码

园区微电网风光储协调优化配置 1 论文2 代码分享2.1 第三题第一问 3 数据与代码 1 论文 2 代码分享 2.1 第三题第一问 function anssq3w1ObjFun(ttt,id); %ttttt(1); tt[750,0,0,1000,600,500]; limttt(1)*200; limmttt(2)*500*0.9-ttt(2)*500*0.1; t1ttt(3)*1000;t2ttt(4)*1…

设计模式--模板方法模式

模板方法模式是一种行为设计模式&#xff0c;它定义了一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中实现。这种模式在许多应用场景中非常有用&#xff0c;例如在实现算法的通用框架、代码重用、封装实现细节以及确保算法的正确执行时。 应用场景 实现算法的通…

ASP+ACCESS多功能论坛程序设计

摘 要 随着计算机的广泛应用&#xff0c;人们已经对网络不再感到陌生。在科技飞速发展的今天&#xff0c;电脑信息技术与各行各业进行了有效的结合。人们在网上可以进行网上购物&#xff0c;网上交友&#xff0c;电子商务&#xff0c;网络营效等等。面对强大的网络功能&#x…

通过Kafka-Logger插件收集流量进行漏洞扫描

通过Kafka-Logger插件收集流量进行漏洞扫描 方案 可以通过APISIX kafka-logger 插件将日志作为 JSON 对象推送到 Apache Kafka 集群中&#xff0c;消费Kafka里的数据格式化后添加到MySQL。 方案详情 1、登录APISIX&#xff0c;启用内置的kafka-logger 插件&#xff1a; 2…

从 0 实现一个文件搜索工具 (Java 项目)

背景 各文件系统下, 都有提供文件查找的功能, 但是一般而言搜索速度很慢 本项目仿照 everything 工具, 实现本地文件的快速搜索 实现功能 选择指定本地目录, 根据输入的信息, 进行搜索, 显示指定目录下的匹配文件信息文件夹包含中文时, 支持汉语拼音搜索 (全拼 / 首字母匹配…

DiffMap:首个利用LDM来增强高精地图构建的网络

论文标题&#xff1a; DiffMap: Enhancing Map Segmentation with Map Prior Using Diffusion Model 论文作者&#xff1a; Peijin Jia, Tuopu Wen, Ziang Luo, Mengmeng Yang, Kun Jiang, Zhiquan Lei, Xuewei Tang, Ziyuan Liu, Le Cui, Kehua Sheng, Bo Zhang, Diange Ya…

深入分析 Android Activity (四)

深入分析 Android Activity (四) 1. Activity 的生命周期详解 Activity 的生命周期方法提供了一组回调&#xff0c;使开发者能够在不同状态下执行相应的逻辑。了解这些方法有助于开发者管理资源和确保应用程序的行为一致。 1.1 onCreate onCreate 是 Activity 的入口点&…

解决go install 网络问题

rootiZbp1hiqzlhh6w05gloffgZ:~# go install mvdan.cc/garblelatest go: mvdan.cc/garblelatest: module mvdan.cc/garble: Get "https://proxy.golang.org/mvdan.cc/garble/v/list": dial tcp 172.217.160.81:443: i/o timeout解决方法 更换阿里代理 rootiZbp1hiq…

浅论未来 IT 和财务结合的趋势

前言 会计核算企业各类业务单据&#xff0c;所有业务部门的数据都会汇流到财务部来&#xff0c;所以会计其实是企业的数据中心&#xff1b;而 IT 技术正是处理数据的利器&#xff0c;可以将重复的流程自动化&#xff0c;还能将财务数据可视化&#xff1b;因此&#xff0c;两者…

docker image prune -f 命令什么用途

docker image prune -f 命令用于清理系统中未被使用的 Docker 镜像。具体来说&#xff0c;它会删除那些未被任何容器使用的悬空镜像&#xff08;dangling images&#xff09;&#xff0c;从而释放磁盘空间。 以下是 docker image prune -f 命令的具体用途和作用&#xff1a; …

SPI通信(STM32)

一、SPI通信 &#xff11;、SPI&#xff08;Serial Peripheral Interface&#xff09;是由Motorola公司开发的一种通用数据总线 &#xff12;、四根通信线&#xff1a;SCK&#xff08;Serial Clock&#xff09;、MOSI&#xff08;Master Output Slave Input&#xff09;、MIS…

【计算理论】【《计算理论导引(原书第3版)》笔记】第〇章:绪论

文章目录 [toc]第〇章&#xff1a;绪论0.1|自动机、可计算性与复杂性计算复杂性理论可计算性理论自动机理论 0.2|数学概念和术语集合关系等价关系 图简单路径连通图圈强连通图 字符串和语言字母表上的字符串空串 w w w的反转&#xff08;倒序&#xff09; x x x和 y y y的连接字…

esp32-idf 开发踩坑记录

现象 直接使用原始命令编译idf.py build 但是提示idf 版本错误 卸载旧版本 编译出错build 问题 然后删除编译文件后&#xff0c;重新编译&#xff0c;还是出错 解决方法1 最后发现是因为项目所在文件夹有中文目录&#xff0c;把项目迁移到英文目录后&#xff0c;重新编译&a…

打破传统相亲模式,这几款靠谱的相亲软件助你脱单

相亲软件在当今社会已经变得越来越普遍&#xff0c;市面上有众多相亲软件可供选择&#xff0c;但哪些相亲软件好用呢&#xff1f;下面介绍几款备受好评的相亲软件&#xff0c;帮助你在茫茫人海中找到那个对的人&#xff01; 1、一伴婚恋 这个APP它最大的优点就是信息真实靠谱…

LIMS系统在汽车检测实验室的应用

随着汽车行业的快速发展&#xff0c;汽车检测实验室的工作量不断增加&#xff0c;对实验室的管理效率和数据准确性提出了更高的要求。建设LIMS系统旨在实现实验室的全面数字化管理&#xff0c;提高工作效率&#xff0c;降低运营成本&#xff0c;并提升数据质量与决策支持能力。…

找出可整除性得分最大的整数 - (LeetCode)

概述 昨天非常忙&#xff0c;上午去做体检&#xff0c;下午去拿报告&#xff0c;晚上和老刘吃撸了一个串&#xff0c;深入交流生活的不易&#xff0c;岁月变化的快&#xff0c;话回算法题&#xff0c;今天的题目比较容易&#xff0c;花了一会就能写出来。 今天这题是&#xf…

Filter和Interceptor

会话 cookie 服务器自动将cookie响应给浏览器 浏览器接收响应回来的数据 自动将cookie存储在本地&#xff0c; 后续请求当中浏览器将cookie携带到服务器 cookie不能跨域&#xff0c;存储在客户端 session 存储在服务器 token------>JWT 存储在客户端&#xff0c; 服务…

[leetcode]第 n个丑数

我们把只包含质因子 2、3 和 5 的数称作丑数&#xff08;Ugly Number&#xff09;。求按从小到大的顺序的第 n 个丑数。 示例: 输入: n 10 输出: 12 解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。 1 2 3 说明: 1 是丑数。 n 不超过1690。 class Solution {public…