基于C#UI Automation自动化测试
步骤
UI Automation 只适用于,标准的win32和 WPF程序
需要添加对UIAutomationClient、 UIAutomationProvider、 UIAutomationTypes的引用
代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Automation;
using System.Windows.Forms;
using System.Windows.Input;namespace WindowsFormsApp1
{public partial class Form1 : Form{private Process processnotepad;private Process processcalc;public Form1(){InitializeComponent();}private void button1_Click(object sender, EventArgs e){//打开笔记本processnotepad = Process.Start(@"C:\Windows\System32\notepad.exe");}private void button2_Click(object sender, EventArgs e){//关闭笔记本processnotepad.Kill();}private void button3_Click(object sender, EventArgs e){//AutomationElement表示 UI 自动化树中的一个 UI 自动化元素,并包含由 UI 自动化客户端应用程序用作标识符的值。//获取当前桌面的根 AutomationElement。AutomationElement desktop = AutomationElement.RootElement;//StringBuilder不在内存中创建新对象,而是动态扩展内存以容纳修改后的字符串。StringBuilder sb = new StringBuilder();//TreeScope(枚举)包含指定 UI 自动化目录树内元素的范围的值。具体参考请点击以下链接进行查看//TreeScope官方链接:https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.automation.treescope?view=windowsdesktop-7.0AutomationElementCollection topWindows = desktop.FindAll(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));//查找计算器for (int i = 0; i < topWindows.Count; i++){AutomationElement topWindow = topWindows[i];sb.AppendLine("Name:" + topWindow.Current.Name + ";ClassName=" + topWindow.Current.ClassName);}MessageBox.Show(sb.ToString());}private void button4_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));AutomationElementCollection btn2 = calcFrame1.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "num9Button"));AutomationElement btn = btn2[0];MessageBox.Show(btn.Current.Name);}private void button5_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));Condition conditionBtn6 = new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),new PropertyCondition(AutomationElement.NameProperty, "六"));var btn6 = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn6);//InvokePattern 表示用于启动或执行单个明确操作的控件,并且这些控件在激活时不保持其状态。//InvokePattern.Pattern 标识 InvokePattern 控件模式。//InvokePattern官方链接 https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.automation.invokepattern?view=windowsdesktop-7.0InvokePattern button6Invoke = (InvokePattern)btn6.GetCurrentPattern(InvokePattern.Pattern);//Invoke() 发送请求以激活控件并启动其单一、明确的操作。button6Invoke.Invoke();Condition conditionBtnPlus = new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),new PropertyCondition(AutomationElement.NameProperty, "加"));var btnPlus = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtnPlus);InvokePattern buttonPlusInvoke = (InvokePattern)btnPlus.GetCurrentPattern(InvokePattern.Pattern);buttonPlusInvoke.Invoke();}private static void InvokeButton(AutomationElement e){InvokePattern Invoke = (InvokePattern)e.GetCurrentPattern(InvokePattern.Pattern);Invoke.Invoke();}private static void ClickCalculatorButton(AutomationElement calcFrame1, String name){Condition conditionBtn = new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),new PropertyCondition(AutomationElement.NameProperty, name));var btn = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn);// MessageBox.Show(btn.Current.Name);if (btn == null){throw new Exception("找不到此" + name + "的按钮");}InvokeButton(btn);}private void button6_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));ClickCalculatorButton(calcFrame1, "三");ClickCalculatorButton(calcFrame1, "乘以");ClickCalculatorButton(calcFrame1, "五");ClickCalculatorButton(calcFrame1, "五");ClickCalculatorButton(calcFrame1, "等于");}[DllImport("user32.dll")]public static extern void SetCursorPos(int x, int y);[DllImport("user32.dll")]public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);private void button7_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "ApplicationFrameWindow"));Condition conditionBtn6 = new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, "Button"),new PropertyCondition(AutomationElement.NameProperty, "六"));var btn6 = calcFrame1.FindFirst(TreeScope.Descendants, conditionBtn6);SetCursorPos((int)btn6.GetClickablePoint().X, (int)btn6.GetClickablePoint().Y);//mouse_event(0x0002 | 0x0004, 0, 0, 0, 0);mouse_event(0x0002, 0, 0, 0, 0); // 模拟鼠标左键按下mouse_event(0x0004, 0, 0, 0, 0); // 模拟鼠标左键弹起}private void button8_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));Condition conditionEdit = new AndCondition( new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"), new PropertyCondition(AutomationElement.NameProperty, "文本编辑器"));AutomationElement txtEdit = calcFrame1.FindFirst(TreeScope.Descendants, conditionEdit);txtEdit.SetFocus();SendKeys.Send("追加123456789");}private const int WM_SETTEXT = 0x000C;[DllImport("user32.dll")]private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);[DllImport("User32.dll")]private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindows);[DllImport("User32.dll")]private static extern Int32 SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, StringBuilder lParam);private void button9_Click(object sender, EventArgs e){AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));Condition conditionEdit = new AndCondition(new PropertyCondition(AutomationElement.ClassNameProperty, "Edit"), new PropertyCondition(AutomationElement.NameProperty, "文本编辑器"));AutomationElement txtEdit = calcFrame1.FindFirst(TreeScope.Descendants, conditionEdit);//.NET提供了一个结构体System.IntPtr专门用来代表句柄或指针。//句柄是对象的标识符,当调用这些API创建对象时,它们并不直接返回指向对象的指针,//而是会返回一个32位或64位的整数值,这个在进程或系统范围内唯一的整数值就是句柄(Handle),//随后程序再次访问对象,或者删除对象,都将句柄作为Windows API的参数来间接对这些对象进行操作。//句柄是一个结构体,简单的来说,它是指针的一个封装,是C#中指针的替代者//句柄链接:https://blog.csdn.net/sinat_40003796/article/details/127244155IntPtr hWnd = FindWindow("Notepad", null);if (!hWnd.Equals(IntPtr.Zero)){IntPtr edithWnd = FindWindowEx(hWnd, IntPtr.Zero, "Edit", null);if (!edithWnd.Equals(IntPtr.Zero)){SendMessage(edithWnd, WM_SETTEXT, IntPtr.Zero, new StringBuilder("重写123456789"));}}else{}}private void button10_Click(object sender, EventArgs e){//点击后有列表的按钮不要当成点击事件AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, "编辑(E)");AutomationElement w2 = calcFrame1.FindFirst(TreeScope.Descendants, myCondition2);ExpandCollapsePattern ecp = (ExpandCollapsePattern)w2.GetCurrentPattern(ExpandCollapsePattern.Pattern);ecp.Expand();}private AutomationElement autoElementGet1(AutomationElement e, string s){Condition myCondition1 = new PropertyCondition(AutomationElement.AutomationIdProperty, s);Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, s);Condition myCondition3 = new PropertyCondition(AutomationElement.AcceleratorKeyProperty, s);Condition myCondition4 = new PropertyCondition(AutomationElement.ClassNameProperty, s);Condition myCondition5 = new PropertyCondition(AutomationElement.AccessKeyProperty, s);Condition myCondition6 = new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, s);Condition myCondition = new OrCondition(myCondition1, myCondition2, myCondition3, myCondition4, myCondition5,myCondition6);AutomationElementCollection myCollection = e.FindAll(TreeScope.Descendants, myCondition);return myCollection[0];}private void button11_Click(object sender, EventArgs e){//随机元素获取AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));AutomationElement filename = autoElementGet1(calcFrame1, "文件(F)");MessageBox.Show("Name:" + filename.Current.Name + ";ClassName=" + filename.Current.ClassName);}private void button12_Click(object sender, EventArgs e){//遍历子控件AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));Condition myCondition1 = new PropertyCondition(AutomationElement.AutomationIdProperty, "MenuBar");AutomationElement MenuBar = calcFrame1.FindFirst(TreeScope.Descendants, myCondition1);AutomationElementCollection MenuBarChildAll = MenuBar.FindAll(TreeScope.Children, Condition.TrueCondition);for (int i = 0; i < MenuBarChildAll.Count; i++){AutomationElement MenuBarChild = MenuBarChildAll[i];MessageBox.Show("Name:" + MenuBarChild.Current.Name + ";ClassName=" + MenuBarChild.Current.ClassName + ";ControlType=" + MenuBarChild.Current.ControlType);}}private void button13_Click(object sender, EventArgs e){processcalc = Process.Start(@"C:\Windows\System32\calc.exe");}private void button14_Click(object sender, EventArgs e){processcalc.Kill();}private void button15_Click(object sender, EventArgs e){//点击后有列表的按钮不要当成点击事件AutomationElement desktop = AutomationElement.RootElement;var calcFrame1 = desktop.FindFirst(TreeScope.Children,new PropertyCondition(AutomationElement.ClassNameProperty, "Notepad"));Condition myCondition1 = new PropertyCondition(AutomationElement.NameProperty, "文件(F)");AutomationElement w1 = calcFrame1.FindFirst(TreeScope.Descendants, myCondition1);ExpandCollapsePattern ecp = (ExpandCollapsePattern)w1.GetCurrentPattern(ExpandCollapsePattern.Pattern);ecp.Expand();Condition myCondition2 = new PropertyCondition(AutomationElement.NameProperty, "退出(X)");AutomationElementCollection myCollection = w1.FindAll(TreeScope.Descendants, myCondition2);AutomationElement w2 = myCollection[0];InvokePattern ipn = (InvokePattern)w2.GetCurrentPattern(InvokePattern.Pattern);ipn.Invoke();Thread.Sleep(500);AutomationElement savefile = calcFrame1.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "保存(S)"));if (savefile != null){InvokePattern savefilebutton = (InvokePattern)savefile.GetCurrentPattern(InvokePattern.Pattern);savefilebutton.Invoke();Thread.Sleep(500);AutomationElement Saveasform = calcFrame1.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "另存为"));AutomationElement edit1 = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "1001"));ValuePattern vp = (ValuePattern)edit1.GetCurrentPattern(ValuePattern.Pattern);vp.SetValue("aaa.txt");AutomationElement savefilepath = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "保存(S)"));InvokePattern savefilepathbutton = (InvokePattern)savefilepath.GetCurrentPattern(InvokePattern.Pattern);savefilepathbutton.Invoke();Thread.Sleep(500);AutomationElement yesSaveasform = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "确认另存为"));AutomationElement issavefilepath = Saveasform.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "是(Y)"));if (issavefilepath != null) {InvokePattern issavefilepathbutton = (InvokePattern)issavefilepath.GetCurrentPattern(InvokePattern.Pattern);issavefilepathbutton.Invoke();}}}}
}
各按钮的功能展示
打开记事本
关闭记事本
获取计算器窗体
修改对应代码,每个按钮点击事件下的的该属性都需要进行修改
结果
获取控件属性
结果
点击按钮
完成计算器计算
鼠标点击按钮
功能是让鼠标去点击,实现点击按钮的功能
追加记事本内容
原始
运行
重写记事本内容
展开按钮列表
随机获取元素方法
遍历记事本菜单栏
打开计算器
控件关闭计算器
保存记事本
工程示例
https://download.csdn.net/download/qq_39397927/88215681
参考
https://www.cnblogs.com/baihuitestsoftware/articles/9047705.html
UI自动化 --- 微软UI Automation_dotNET跨平台的博客-CSDN博客
相关文章:

基于C#UI Automation自动化测试
步骤 UI Automation 只适用于,标准的win32和 WPF程序 需要添加对UIAutomationClient、 UIAutomationProvider、 UIAutomationTypes的引用 代码 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.D…...

深入了解Linux运维的重要性与最佳实践
Linux作为开源操作系统的代表,在企业级环境中的应用越来越广泛。而在保障Linux系统的正常运行和管理方面,Linux运维显得尤为关键。本文将介绍Linux运维的重要性以及一些最佳实践,帮助读者更好地了解和掌握Linux系统的运维技巧。 首先…...
90 | Python人工智能篇 —— 深度学习算法 Keras基于卷积神经网络的情感分类
情感分类是自然语言处理(NLP)领域的一个重要任务,它旨在将文本划分为积极、消极或中性等不同情感类别。深度学习技术,尤其是卷积神经网络(CNN),在情感分类任务中取得了显著的成果。Keras作为一个高级的深度学习框架,提供了便捷易用的工具来构建和训练情感分类模型。 文…...
自然语言处理从入门到应用——LangChain:记忆(Memory)-[记忆的类型Ⅲ]
分类目录:《自然语言处理从入门到应用》总目录 对话令牌缓冲存储器ConversationTokenBufferMemory ConversationTokenBufferMemory在内存中保留了最近的一些对话交互,并使用标记长度来确定何时刷新交互,而不是交互数量。 from langchain.me…...
【ARM 嵌入式 编译系列 10.3 -- GNU elfutils 工具小结】
文章目录 什么是 GNU elfutils?GNU elfutils 常用工具有哪些?objcopy 常用参数有哪些?GNU binutils和GNU elfutils区别是什么? 上篇文章:ARM 嵌入式 编译系列 10.2 – 符号表与可执行程序分离详细讲解 什么是 GNU elfu…...

黑马项目一阶段面试 项目介绍篇
我完成了一个外卖项目,名叫苍穹外卖,是跟着黑马程序员的课程来自己动手写的。 项目基本实现了外卖客户端、商家端的后端完整业务。 商家端分为员工管理、文件上传、菜品管理、分类管理、套餐管理、店铺营业状态、订单下单派送等的管理、数据统计等&…...
重构内置类Function原型上的call方法
重构内置类Function原型上的call方法 // > 重构内置类Function原型上的call方法 ~(function () {/*** call: 改变函数中的this指向* params* context 可以不传递,传递必须是引用类型的值,因为后面要给它加 fn 属性**/function myCall(context) {/…...

Nginx之lnmp架构
目录 一.什么是LNMP二.LNMP环境搭建1.Nginx的搭建2.安装php3.安装数据库4.测试Nginx与PHP的连接5.测试PHP连接数据库 一.什么是LNMP LNMP是一套技术的组合,Llinux,Nnginx,Mmysql,Pphp 首先Nginx服务是不能处理动态资源请求&…...

C# 使用FFmpeg.Autogen对byte[]进行编解码
C# 使用FFmpeg.Autogen对byte[]进行编解码,参考:https://github.com/vanjoge/CSharpVideoDemo 入口调用类: using System; using System.IO; using System.Drawing; using System.Runtime.InteropServices; using FFmpeg.AutoGen;namespace F…...
websocket是多线程的嘛
经过测试, onOpen事件的threadId和onMessage的threadId是不一样的,但是onMessage的threadId一直是同一个,就是说收消息的部分是单线程的,收到第一个Message后如果给它sleep较长时间,期间收到第二个,效果是它在排队&am…...
CentOS7.9 禁用22端口,使用其他端口替代
文章目录 业务场景操作步骤修改sshd配置文件修改SELinux开放给ssh使用的端口修改防火墙,开放新端口重启sshd生效 相关知识点介绍sshd服务SELinux服务firewall.service服务 业务场景 我们在某市实施交通信控平台项目,我们申请了一台服务器,用…...

2023国赛 高教社杯数学建模ABCDE题思路汇总分析
文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料 0 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 全国大学生数学建模…...

【网络层+数据链路层】深入理解IP协议和MAC帧协议的基本原理
文章目录 前言一、IP协议二、MAC帧协议 1.以太网2.以太网帧(MAC帧)格式报头3.基于协议讲解局域网转发的原理总结 前言 为什么经常将TCP/IP放在一起呢?这是因为IP层的核心工作就是通过IP地址来定位主机的,具有将一个数据报从A主机…...
银行家算法【学习算法】
银行家算法【学习算法】 前言版权推荐银行家算法7.避免死锁7.1 系统安全状态7.2 利用银行家算法避免死锁 Java算法实现代码结果 最后 前言 2023-8-14 18:18:01 以下内容源自《【学习算法】》 仅供学习交流使用 版权 禁止其他平台发布时删除以下此话 本文首次发布于CSDN平台…...
萤石直播以及回放的接入和销毁
以下基于vue项目 1.安装 npm i ezuikit-js 2、导入 main.js中 import EZUIKit from "ezuikit-js"; //导入萤石Vue.use(EZUIKit); 3、创建容器 <div class"video"><div id"video-container"></div><!-- <iframe :src…...
C语言易错知识点总结2
函数 第 1 题(单选题) 题目名称: 能把函数处理结果的二个数据返回给主调函数,在下面的方法中不正确的是:( ) 题目内容: A .return 这二个数 B .形参用数组 C .形参用二个指针 D .用…...

Go学习-Day1
Go学习-Day1 个人博客:CSDN博客 打卡。 Go语言的核心开发团队: Ken Thompson (C语言,B语言,Unix的发明者,牛人)Rob Pike(UTF-8发明人)Robert Griesemer(协助HotSpot编译器,Js引擎V8) Go语言有静态语言的…...

冠达管理:机构密集调研医药生物股 反腐政策影响受关注
进入8月,跟着反腐事件发酵,医药生物板块呈现震荡。与此一起,组织出资者对该板块上市公司也展开了密集调研。 到昨日,8月以来就有包含南微医学、百济神州、维力医疗、方盛制药等12家医药生物板块的上市公司接受组织调研,…...

安装Tomac服务器——安装步骤以及易出现问题的解决方法
文章目录 前言 一、下载Tomcat及解压 1、选择下载版本(本文选择tomcat 8版本为例) 2、解压安装包 二、配置环境 1、在电脑搜索栏里面搜索环境变量即可 2、点击高级系统设置->环境变量->新建系统变量 1) 新建系统变量,变量名为…...

JVM 性能优化思路
点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ 一般在系统出现问题的时候,我们会考虑对 JVM 进行性能优化。优化思路就是根据问题的情况,结合工具进行问题排查,针对排查出来的可能问题…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...

spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...