JavaWeb 速通Filter

news2024/11/24 6:34:34

目录

一、Filter快速入门

        1.基本介绍 : 

        2.基本原理 : 

        3.入门实例 : 

        4.生命周期 : 

二、FilterConfig和FilterChain

        1.FilterConfig : 

            1° 基本介绍

            2° 应用实例

        2.FilterChain : 

            1° 基本介绍 

            2° 基本原理 

            3° 应用实例 

            4° 使用细节


一、Filter快速入门

        1.基本介绍 : 

        Filter,过滤器,是JavaWeb的三大组件之一 (Servlet 程序、 Listener 监听器、 Filter过滤器 )。Listener和Filter本质也属于Servlet规范,但由于其独立的功能而单独作为了JavaWeb三大组件。
        Filter是接口,使用频率很高。Filter除了可以解决传统验证方式造成的代码冗余,功能重复的问题,还可以应用于日志操作,权限检查,事务管理等场景。

        2.基本原理 : 

        (1) 当浏览器端向服务器端发送过来HTTP请求时,Tomcat会根据web.xml配置文件中配置的过滤器和指定过滤器的url-pattern规则——来判断当前请求是否需要走过滤器。PS : 过滤的规则可以由程序员手动指定。

        (2) 如果判断不需要走过滤器,就直接访问Web资源(servlet,web静态页面等)。

        (3) 如果判断需要,Tomcat就会根据业务需求进行验证,如果验证合法,就继续访问;如果验证不合法,就进行返回。PS : 具体返回的URL也可以由程序员手动指定。

        (4) Tomcat在调用servlet等Web资源之前,会先进行Filter的匹配——即根据请求的URL(由req对象封装),到管理Filter的URL的容器中去匹配,若匹配成功,再去管理Filter的容器中找到对应的Filter实例,并调用它的doFilter方法;若没有匹配成功,就直接访问web资源。(联系手写Tomcat底层中用于管理servlet的两个Map容器)

        3.入门实例 : 

                定义login.jsp页面,用于用户登录的操作,数据提交到LoginCheckServlet,若password等于233,认为是管理员登录,请求转发到administration.jsp页面(用户管理页面)。administration.jsp页面定义在target包下,定义过滤器LoginFilter,过滤规则为/target/*

                login.jsp页面代码如下 : 

<%--
    User : Cyan_RA9
    Version : 21.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>login</title>
    <style>
        table, td {
            border: cornflowerblue 2px solid;
            background-color: lightcyan;
            border-collapse: collapse;
            padding: 5px;
        }
    </style>
</head>
<body>
<form action="<%= request.getContextPath() %>/loginCheckServlet" method="post">
    <table>
        <tr>
            <th colspan="2">Manage the login</th>
        </tr>
        <tr>
            <td>Username : </td>
            <td><input type="text" name="username"/></td>
        </tr>
        <tr>
            <td>Password : </td>
            <td><input type="password" name="password"/></td>
        </tr>
        <tr>
            <td><input type="submit" value="submit"/></td>
            <td><input type="reset" value="reset"/></td>
        </tr>
    </table>
</form>
</body>
</html>

                页面效果如下 : 

                LoginCheckServlet类代码如下 : 

package filter;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

/**
 * @author : Cyan_RA9
 * @version : 21.0
 */
@WebServlet(urlPatterns = {"/loginCheckServlet"})
public class LoginCheckServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        RequestDispatcher requestDispatcher = null;

        if ("233".equals(password)) {
            //若验证合法,向session中放入用户名
            req.getSession().setAttribute("username", username);

            requestDispatcher = req.getRequestDispatcher("/target/administration.jsp");
            requestDispatcher.forward(req, resp);
        } else {
            requestDispatcher = req.getRequestDispatcher("/login.jsp");
            requestDispatcher.forward(req, resp);
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

                administration.jsp页面代码如下 : 

<%--
    User : Cyan_RA9
    Version : 21.0
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>target</title>
    <%--<base href="<%= request.getContextPath() %>/img/"/>--%>
    <style>
        table, td {
            border: 2px lightpink solid;
            background-color: lightcyan;
            border-collapse: collapse;
            padding: 10px;
            margin-left: auto;
            margin-right: auto;
        }
    </style>
</head>
<body>
<table width="500px">
    <tr>
        <th>ID</th>
        <th>Username</th>
        <th>Function</th>
    </tr>
    <tr>
        <td>100011</td>
        <td>Cyan</td>
        <td><a href="none">删除用户</a></td>
    </tr>
    <tr>
        <td>100023</td>
        <td>Rain</td>
        <td><a href="none">删除用户</a></td>
    </tr>
    <tr>
        <td>100033</td>
        <td>Ice</td>
        <td><a href="none">删除用户</a></td>
    </tr>
    <tr>
        <td>100041</td>
        <td>Five</td>
        <td><a href="none">删除用户</a></td>
    </tr>
    <tr>
        <td>100099</td>
        <td>Irving</td>
        <td><a href="none">删除用户</a></td>
    </tr>
</table>
</body>
</html>

                页面效果如下 : 

                定义LoginFilter过滤器对用户的非法访问进行拦截,防止非管理员非法访问用户管理界面。LoginFilter类代码如下 : 

package filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

import java.io.IOException;

public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("LoginFilter is initialized~");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("LoginFilter's doFilter method is invoked~");
        /**
         * (1) 每次调用该Filter对象时,都会动态绑定调用doFilter方法;
         * (2) 若doFilter方法中没有调用继续请求的方法,那么对请求的资源的访问就会卡在这里。
         * (3) Tomcat在调用Filter之前,就已经创建好了req和resp对象,并且req中已经封装好了
         *      HTTP请求的相关信息。因此,可以通过req对象来获取到这些信息,例如URL,session,
         *      等等,从而实现日志操作,权限检查,事务管理等业务需求。
         * (4) 可以通过filterChain对象的doFilter方法将servletRequest对象和
         *       servletResponse对象传递下去。
         * (5) 特别注意:请求转发不经过过滤器!(在服务器端)
         */

        //动态---动态绑定的使用
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();

        //session中的属性可能之后会用到(eg : log),因此可以单独做接收。
        String username = (String) session.getAttribute("username");
        if (username != null) {
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            RequestDispatcher requestDispatcher = servletRequest.getRequestDispatcher("/login.jsp");
            requestDispatcher.forward(servletRequest, servletResponse);
        }
        /**
         * 关于filterChain.doFilter方法 :
         * (1) 该方法执行,会继续访问URL的目标资源;
         * (2) 创建好的servletRequest对象和servletResponse对象会传递给目标资源(servlet/jsp,etc)
         * (3) 因此,目标资源中获得的这两个对象是相同的对象 (同一次HTTP请求中)
         */
    }

    @Override
    public void destroy() {
        System.out.println("LoginFilter is destroyed~");
    }
}

                在web.xml配置文件中配置Filter,代码如下 : 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/target/*</url-pattern>
    </filter-mapping>
    <!--
        此处的<url-pattern>即指过滤规则,当请求的URL满足该条件时,
        都需要走该过滤器。这时Tomcat会调用该Filter的doFilter()方法。
        (回顾URL四种匹配模式)
    -->
</web-app>

                运行效果 : (如下GIF)

        4.生命周期 : 

        (1) 当Web工程启动时,Tomcat会根据反射机制创建对应的Filter实例(一个Filter只创建一次),并放入Tomcat维护的容器中保存。

        (2) Tomcat会执行对应Filter的默认无参构造器和init方法(一次HTTP请求中,init方法只会调用一次)。Filter实例会常驻内存

        (3) 在创建Filter实例时,Tomcat会同时创建一个FilterConfig对象,并通过init方法传入该对象。程序员可以通过FilterConfig对象获取到该Filter的相关配置信息。

        (4) 当一个HTTP请求从客户端发来时,Tomcat会判断该HTTP请求的URL是否与某个过滤器的<url-pattern>相匹配,若匹配,就会调用对应过滤器的doFilter方法。并且,Tomcat会同时创建ServletRequest对象 和 ServletResponse对象,以及FilterChain对象,并通过doFilter方法传入

        (5) Web工程停止时,销毁Filter实例,并调用destroy方法。


二、FilterConfig和FilterChain

        1.FilterConfig : 

            1° 基本介绍

        FilterConfig是Filter过滤器的配置类。FilterConfig对象的作用是获取Filter过滤器的配置内容。

            2° 应用实例

                在web.xml中重新配置一个filter,web.xml代码如下 : 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/target/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>FilterConfig_Demo</filter-name>
        <filter-class>filter.FilterConfig_Demo</filter-class>
        <init-param>
            <param-name>color</param-name>
            <param-value>cyan</param-value>
        </init-param>
        <init-param>
            <param-name>sport</param-name>
            <param-value>basketball</param-value>
        </init-param>
        <init-param>
            <param-name>fruit</param-name>
            <param-value>grape</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FilterConfig_Demo</filter-name>
        <url-pattern>/filterConfig_Demo</url-pattern>
    </filter-mapping>
</web-app>

                FilterConfig_Demo类代码如下 : 

package filter;

import jakarta.servlet.*;

import java.io.IOException;
import java.util.Enumeration;

public class FilterConfig_Demo implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //获取当前过滤器的名称
        String filterName = filterConfig.getFilterName();
        System.out.println("filterName = " + filterName);

        //获取当前过滤器中配置的参数(根据name获取指定参数)
        String color = filterConfig.getInitParameter("color");
        String fruit = filterConfig.getInitParameter("fruit");
        String sport = filterConfig.getInitParameter("sport");
        System.out.println("color = " + color);
        System.out.println("fruit = " + fruit);
        System.out.println("sport = " + sport);

        //获取当前过滤器中配置的全部参数
        Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            System.out.println("parameter's name = " + initParameterNames.nextElement());
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        RequestDispatcher requestDispatcher = servletRequest.getRequestDispatcher("/Listener_Filter/login.jsp");
        requestDispatcher.forward(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

                运行效果 : (如下GIF)

        2.FilterChain : 

            1° 基本介绍 

        FilterChain,过滤器链。在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链

            2° 基本原理 

                如下图所示 : 

            3° 应用实例 

                定义两个过滤器,分别为Filter_Demo1和Filter_Demo2,并且在web.xml配置文件中按照1--->2的顺序配置
                web.xml配置文件代码如下 : 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <filter>
        <filter-name>Filter_Demo1</filter-name>
        <filter-class>filter.Filter_Demo1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter_Demo1</filter-name>
        <url-pattern>/img/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>Filter_Demo2</filter-name>
        <filter-class>filter.Filter_Demo2</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>Filter_Demo2</filter-name>
        <url-pattern>/img/cornflower.jpg</url-pattern>
    </filter-mapping>
</web-app>

                Filter_Demo1类代码如下 : 

package filter;

import jakarta.servlet.*;

import java.io.IOException;

public class Filter_Demo1 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter_Demo1 ———— doFilter's fore code");

        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("Filter_Demo1 ———— doFilter's end code");
    }
}

                Filter_Demo2类代码如下 :

package filter;

import jakarta.servlet.*;

import java.io.IOException;

public class Filter_Demo2 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter_Demo2 ———— doFilter's fore code");

        filterChain.doFilter(servletRequest, servletResponse);

        System.out.println("Filter_Demo2 ———— doFilter's end code");
    }
}

                运行效果 : (GIF)

            4° 使用细节

        (1) 同一次HTTP请求中,由同一线程负责通过多个Filter以及对目标资源的访问。(多个Filter使用同一个request对象)

        (2) 只有当HTTP请求的URL与配置的过滤器的url-pattern匹配时,过滤器的doFilter方法才会被执行;并且如果同一次HTTP请求中有多个Filter被匹配成功,就会顺序执行,形成一个Filter调用链。(多个Filter的执行顺序,与web.xml配置文件中配置的顺序一致)

        (3) filterChain.doFilter()方法执行时,将执行下一个匹配到的过滤器的doFilter方法。如果当前过滤器之后已经没有其他匹配到的过滤器,就执行到目标资源

        System.out.println("END--------------------------------------------------------------------------------------------------------------------------------");

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

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

相关文章

【Python原创设计】基于Python Flask 机器学习的全国+上海气象数据采集预测可视化系统-附下载链接以及详细论文报告,原创项目其他均为抄袭

基于Python Flask 机器学习的全国上海气象数据采集预测可视化系统 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 在信息科技蓬勃发展的当代&#xff0c;我们推出了一款基于Python Flask的全国上海气象数…

斯里兰卡生态系统服务价值量计算

斯里兰卡生态服务价值计算 一、引言 生态系统服务价值是指人类间接或直接从生态系统各服务功能中获得的收益&#xff0c;对人类社会福祉起着极其重要的贡献。生态系统服务价值核算作为一项基础性研究工作&#xff0c;对生态安全格局的构建、生态补偿以及生态文明建设等研究有重…

【Linux】socket编程(一)

目录 预备知识 理解源ip地址和目的ip地址 认识端口号 理解"端口号"和"进程ID" 认识TCP和UDP协议 网络字节序 socket编程接口 socket常见API socket bind listen accept conncet sockaddr与sockaddr_in socket的使用(简易UDP网络程序的编…

17款奔驰S400升级原厂无钥匙进入系统,提升您的便利性

奔驰无钥匙进入功能&#xff0c;只要身上装着车钥匙进入车内&#xff0c;车辆就能感应到钥匙的存在&#xff0c;这时只需按下启动键就可启动车辆了 奔驰无钥匙进入功能主要有两大使用体验&#xff0c;首先就是要注意主驾驶位车门的有效检测距离不小于1.5m&#xff0c;其他门钥匙…

2022年09月 C/C++(三级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;课程冲突 小 A 修了 n 门课程, 第 i 门课程是从第 ai 天一直上到第 bi 天。 定义两门课程的冲突程度为 : 有几天是这两门课程都要上的。 例如 a11&#xff0c;b13&#xff0c;a22&#xff0c;b24 时, 这两门课的冲突程度为 2。 现在你需要求的是这 n 门课中冲…

vue 中 axios 的安装及使用

vue 中 axios 的安装及使用 1. axios 安装2. axios使用 1. axios 安装 首先&#xff0c;打开当前的项目终端&#xff0c;输入 npm install axios --save-dev验证是否安装成功&#xff0c;检查项目根目录下的 package.json,其中的 devDependencies 里面会多出一个axios及其版本…

【中国善网】资源对接(场地捐赠)公示

-----仰和百花心理咨询认领安利公益基金会捐赠场地 近日&#xff0c;经过中国善网与安利公益基金会的沟通与对接&#xff0c;仰和百花心理咨询获得免费认领安利公益基金会场地&#xff08;安利深圳体验馆&#xff09;8月22-25日为期4天的使用权&#xff0c;特此公示。为推动公…

(嵌入式c语言)类型修饰符

类型修饰符 对内存资源存储位置的限定 auto 默认的类型修饰符 修饰的变量可读可写 register 因为你内部寄存器比较少&#xff0c;使用此类型修饰符&#xff0c;会告诉编译器尽量把此数据放到寄存器。 CPU内部寄存器是编号来定义&#xff0c;无地址编号&#xff0c;所以r…

网络控价方法论

品牌为什么要做控价&#xff1f; 不做控价的品牌&#xff0c;会面对价值受损、经销商流失、口碑下降的局面&#xff0c;因为低价不是一家店铺的行为&#xff0c;会随着时间的推移&#xff0c;不断蔓延&#xff0c;当越来越多的店铺低价&#xff0c;则表示渠道越来越乱&#xf…

亚马逊或将更改付款期限?卖家如何有效应对?

据外媒报道&#xff0c;亚马逊将更改其付款期限&#xff0c;英国和欧洲的卖家必须等到商品交付一周后才能收到款项。这项变更将于9月1日至6日分阶段生效&#xff0c;目前亚马逊已经向欧洲和英国的卖家发出通知。 一、亚马逊付款期限调整有何影响&#xff1f; 据了解&#xff…

【Python原创设计】基于Python Flask的上海美食信息与可视化宣传网站项目-附下载方式以及往届优秀论文,原创项目其他均为抄袭

基于Python Flask的上海美食信息与可视化宣传网站&#xff08;获取方式访问文末官网&#xff09; 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 随着大数据和人工智能技术的迅速发展&#xff0c;我们设…

【React基础全篇】

文章目录 一、关于 React二、脚手架2.1 create-react-app 脚手架的使用2.2 项目目录解析2.3 抽离配置文件2.4 webpack 二次封装2.4.1 集成 css 预处理器2.4.2 配置解析别名 2.5 setupProxy 代理 三、JSX3.1 jsx 语法详解3.2 React.createElement 四、组件定义4.1 类组件4.2 函数…

日常中msvcp140.dll丢失是什么原因,msvcp140.dll丢失4个解决方法

在计算机编程过程中&#xff0c;我们可能会遇到各种错误和问题。其中&#xff0c;丢失msvcp140.dll文件是一个常见的问题。msvcp140.dll是Microsoft Visual C 2015 Redistributable的一部分&#xff0c;它包含了运行许多应用程序所需的运行时库。当这个文件丢失时&#xff0c;可…

【Python原创设计】基于Python Flask的全国气象数据采集及可视化系统-附下载方式以及项目参考论文,原创项目其他均为抄袭

基于Python Flask的全国气象数据采集及可视化系统 一、项目简介二、项目技术三、项目功能四、运行截图五、分类说明六、实现代码七、数据库结构八、源码下载 一、项目简介 本项目是一个基于Web技术的实时气象数据可视化系统。通过爬取中国天气网的各个城市气象数据&#xff0c…

【Go语言】基于Socket编程的P2P通信程序示例

Go语言的Socket编程实现为开发者提供了一种高效且强大的方式来实现网络通信。通过Go语言的并发模型和内置的网络库&#xff0c;如net包&#xff0c;开发者可以轻松地创建基于套接字的通信应用。Go语言的goroutine和channel机制使并发处理变得简单&#xff0c;能够轻松处理多个连…

Address already in use: bind 如何解决端口号被占用

Address already in use: bind 程序报错&#xff0c;说明端口号已经被占用了。在不重启计算机的情况下&#xff0c;可通过如下方式解决 一&#xff1a; winR 快捷键 输入cmd指令打开黑框 二&#xff1a;输入指令 netstat -ano 查看端口号 三&#xff1a;根据端口号&#xff0c…

色差分量接口ESD静电保护推荐TVS二极管:DW03DLC-B-S和DW05R-E

YCbCr/YPbPr色差分量接口是S-Video端子的升级产品&#xff0c;支持1080P高清&#xff0c;由红、绿、蓝三种颜色的线组成&#xff0c;其中&#xff0c;蓝色和红色分别传输蓝色差信号&#xff08;Cb/Pb&#xff09;和红色差信号&#xff08;Cr/Pr&#xff09;&#xff0c;而绿色传…

【vue3+ts项目】配置husky+配置commitlint

上一篇文章中配置了eslint校验代码工具 【vue3ts项目】配置eslint校验代码工具&#xff0c;eslintprettierstylelint 1、配置husky 每次手动执行命令才能格式化代码&#xff0c;如果有人没有格式化就提交到远程仓库&#xff0c;这个规范就起不到作用了&#xff0c;所有需要强…

【C++初阶】模拟实现vector

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习C和算法 ✈️专栏&#xff1a;C航路 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac; 点赞&#x1…

【测试】pywinauto的简单使用(安装、常用对象、元素控件、鼠标操作、键盘操作)

1.说明 pywinauto是一个用于自动化Python 模块&#xff0c;适合Windows系统的软件&#xff08;GUI&#xff09;&#xff0c;可以通过Pywinauto遍历窗口&#xff08;对话框&#xff09;和窗口里的控件&#xff0c;也可以控制鼠标和键盘输入&#xff0c;所以它能做的事情比之前介…