目录： 1、下载安装MySQL 2、在安装目录新建配置 3、添加环境变量 4、安装 5、启动服务 6、卸载 现在 Windows 下安装 MySQL 的时候需要首先下载 MySQL Installer，通过这个软件来联网安装管理不同版本的 MySQL，但是这个软件默认是将 MySQL 安装在 C 盘的，修改安装路径的地方也藏的很隐蔽，并且由于安装时 MySQL Installer 需要联网下载安装包，这对于内网里的机器无疑就是很不友好的。但是从 Oracle 官网下载到的 MSI Installer 程序只是解压出了 MySQL 程序，并没有进行任何的环境变量配置、服务配置，那么就需要通过手动配置程序信息。 1、下载安装MySQL 最新版本下载链接：MySQL :: Download MySQL Community Server 旧版本下载链接：MySQL :: Download MySQL Community Server (Archived Versions) 选择下载某一个版本的 MSI 安装程序或者 ZIP 压缩包，下载完成之后进行安装或解压。 2、在安装目录新建配置 下文中的 MySQL 安装目录以 D:\Program\Environment\MySQL\MySQL Server 5.7 为例： 安装目录下创建一个 “data” 文件夹 安装目录下创建一个 “my.ini” 文本文件，向其中写入以下内容（文件路径根据实际修改）： [mysqld] # mysql 安装目录 basedir="D:\Program\Environment\MySQL\MySQL Server 5.7" # mysql 数据库的数据存放目录 datadir="D:\Program\Environment\MySQL\MySQL Server 5.7\data" sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES # MySQL服务器监听的端口 port=3306 # 服务端编码方式 character-set-server=utf8mb4 [clinet] # 客户端编码方式 loose-default-character-set=utf8mb4 # 端口号设置 port=3306 [WinMySQLadmin] Server="D:\Program\Environment\MySQL\MySQL Server 5.7\bin\mysqld.exe" 3、添加环境变量 右键 “开始菜单” -> “系统” -> “高级系统设置” -> “环境变量” 向 Path 中添加环境变量，值为 MySQL 安装目录下的 bin 文件夹： D:\Program\Environment\MySQL\MySQL Server 5.7\bin 4、安装 上面环境变量配置没有问题的话，就可以在 cmd 窗口中使用 mysqld 命令了。 此时以管理员身份运行 cmd 窗口，执行命令来初始化相关 data 文件： # 在前面配置好的 data 文件夹下会生成初始化的文件 mysqld --initialize-insecure --user=mysql 安装 MySQL 服务： mysqld -install 5、启动服务 可以通过以下命令启动 MySQL 服务： net start mysql 或者在 ”服务“ 窗口中找到 ”MySQL“ 这项服务，右键启动即可： 服务窗口可通过在“运行”窗口输入 “services.msc” 来启动，或者右键 开始菜单 -> 计算机管理 -> 服务和应用程序 -> 服务 找到。 在启动过程中有可能会出现报错： 在 MySQL 的服务属性中可以看到这项服务可执行文件的程序路径是不正确的： 这个窗口里面没有提供可以改这个路径的地方，查了一下，得需要到注册表中改，在注册表中（Win + R 运行窗口中输入“regedit”回车打开）找到 “HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MySQL” 这个路径，修改其中 ImagePath 的值，将引号里的路径替换为本地 MySQL 安装文件的实际路径（就只替换前面的路径，其他的不用改）： 保存退出之后，再到 “服务” 窗口中刷新一下，可执行文件的路径变成了新的路径之后再次启动即可成功启动 MySQL 服务。 目前本地运行的 MySQL 服务用 root 用户就可以登录，密码为空 MySQL 修改密码： 连接到数据库之后用 SQL 语句为 root 用户更改密码： alter user '用户名'@'localhost' identified by '新密码'; 修改完之后，刷新权限信息： flush privileges; 也可以在 MySQL 控制台中使用 mysqladmin 命令修改用户密码： # 新密码不需要加引号，否则会报错 mysqladmin -u [用户名] -p password [新密码]; 6、卸载 以管理员身份执行命令： mysqld -remove 删除服务： sc delete mysql 删除注册表文件： HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Application\MySQL HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\MySQL HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\services\eventlog\Application\MySQL 参考资料： MySQL8.0绿色版本——最纯净的安装体验(免去卸载不掉只能重做系统的‘囧‘境)_mysql8.0 绿色安装-CSDN博客 mysql 启动提示：错误2系统找不到指定文件；（本地计算机上的mysql服务启动后停止，某些服务在未由其他服务或程序使用时将自动停止）_无法编辑imagepath-CSDN博客
目录： 一、Docker 1.1、什么是 Docker 1.2、安装 Docker 1.3、更改镜像源 二、基本概念 2.1、镜像（Image） 2.2、容器（Container） 2.3、标签（Tag） 2.4、仓库（Repository）与注册中心（Registry） 二、命令 2.1、镜像管理 从 Dockerfile 构建镜像： 从远程仓库拉取某个镜像： 将本地镜像推送到远程仓库 列出本地所有镜像 列出与关键词匹配的本地镜像 查看镜像的详细信息（以 JSON 格式输出） 查看镜像的分层历史（各层的创建指令和大小） 删除本地镜像文件 删除所有悬空镜像 删除所有未被任何容器使用的镜像 将镜像保存为 tar 文件（一般用于离线迁移） 从 tar 文件加载镜像到本地 给镜像打标签： 2.2、容器启停 创建并启动容器 只创建容器，不启动 启动已经创建的容器： 在运行的容器中执行命令 停止运行中的容器： 强制停止容器： 重启容器： 2.3、容器管理 查看运行中的容器 删除已停止的容器 删除所有已停止容器 查看容器的标准输出和错误日志： 查看容器内运行的进程 试试监控容器的 CPU、内存、网络等资源使用情况 在主机与容器之间复制文件 导出容器为 tar 文件： 从 tar 文件导入为镜像： 2.4、标签管理 环境：ubuntu 24.04 一、Docker 1.1、什么是 Docker Docker是一个开源平台，用于将应用程序及其所有依赖项打包成标准的容器，从而实现“一次构建，到处运行”。 Docker 与传统虚拟机（Virtual Machine，VM）都是实现环境隔离和应用封装的技术，但它们在架构、性能、资源利用和使用场景上有本质区别。 Docker 容器除了运行其中的应用外，基本不消耗额外的系统资源，保证应用性能的同时，尽量减少系统开销。 传统虚拟机方式运行 N 个不同的应用就要起 N 个不同的虚拟机（每个虚拟机都要单独分配独占的内存、磁盘等资源），而 Docker 只需要启动 N 个隔离的“很薄的”容器，并将应用放进容器内即可。应用获得的是接近原生的运行性能。 对比维度 Docker（容器） 虚拟机（VM） 操作系统 共享宿主机内核 每个 VM 一个完整 OS 启动速度 秒级（0.1～2s） 分钟级 镜像大小 MB ~ 几百 MB GB 级 资源开销 极低 高 性能 接近裸机 有一定损耗 隔离性 进程级隔离 硬件级隔离 安全性 较弱（共享内核） 更强 可移植性 非常强 一般 运维成本 低 高 密度 单机可跑数百容器 单机只能跑少量 VM 虚拟机 = 在硬件上虚拟出一整台“电脑”，解决的是“硬件虚拟化”问题 Docker = 在操作系统上隔离出一个“进程运行环境”，解决的是“应用交付与环境一致性”问题 可以粗略类比为： 虚拟机：每个租户 独立一套房子（含水电） Docker：每个租户 独立一个房间，共用整栋楼的水电 Docker 官网：Docker: Accelerated Container Application Development Docker 官方文档：Manuals | Docker Docs 国内中文翻译文档：Docker中文文档（Docker官方文档，Docker官方教程） 1.2、安装 Docker 使用官方安装脚本： # 下载并执行Docker官方安装脚本 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 或者通过添加 Docker 软件源安装： sudo apt-get update sudo apt-get install ca-certificates curl -y sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://mirrors.cloud.tencent.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://mirrors.cloud.tencent.com/docker-ce/linux/ubuntu/ \ $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin 用上面任何一种方法安装完成 Docker 之后启动： # 启动Docker服务 sudo systemctl start docker # 设置开机自启 sudo systemctl enable docker 执行以下命令，检查安装结果： sudo docker info 输出版本信息则说明安装成功。 1.3、更改镜像源 需要说明的是，以往在国内使用很普遍的腾讯云、阿里云和各个大学的 Docker 镜像站点自从 2024 年之后都陆续不可用，现在可使用的镜像源已经很少，也不确定能用多久， 开发者镜像 - 免费手机工具 站长工具 源代码查看器 Docker镜像极速下载服务 - 毫秒镜像 Docker 镜像免费公共测试访问入口 | 轩辕镜像免费版 而在国内买了云服务商的服务器的话，可以使用其提供的内网 Docker 镜像，不过只能在其服务器上使用而无法在外网机器上使用。 腾讯云：腾讯云 - 安装 Docker 并配置镜像加速源，阿里云：阿里云 - 容器镜像服务，文档中明确写 https://mirror.ccs.tencentyun.com 只支持内网访问，不再支持外网域名访问加速。 找到配置镜像源的文件（如果文件不存在请新建） /etc/docker/daemon.json ，写入如下内容： { "registry-mirrors" : [ "https://docker.m.daocloud.io", "https://docker.xuanyuan.me", "https://docker.1ms.run" ] } 之后重新启动服务： sudo systemctl daemon-reload sudo systemctl restart docker 执行 docker info 命令检查配置是否成功，如果输出内容中 Registry Mirrors 一项变成了配置的镜像源，则说明更改镜像源成功。 二、基本概念 2.1、镜像（Image） 镜像是一个用于创建容器（Container）只读模板，可以粗略理解为面向对象编程中的“类”（Class），其包含了运行一个软件所需的代码、运行环境、库、环境变量和配置文件等。 镜像具有如下特点： 不可变：镜像一旦构建完成，内容便默认不可修改 分层结构：镜像采用联合文件系统（UnionFS），以分层方式组织文件，使得多个镜像可以共享相同的基础层，从而节省空间 可分发：镜像可以被推送到远程注册中心（如 Docker Hub）或从注册中心拉取，实现跨平台使用 2.2、容器（Container） 容器时镜像的运行实例，类似于“对象”，是镜像这个“类”的一个具体实例。当启动一个镜像时，Docker 会基于该镜像创建一个容器，并在其中运行应用程序（例如Nginx、MySQL等）。 容器的特点： 可读写：虽然镜像不可修改，但容器在镜像的基础上增加了一个可写层，所有对系统的修改都发生在这个层中。 具有生命周期：可以启动、停止、暂停、删除。 资源隔离：容器之间默认隔离无法交互的，通过 Linux 的 Namespace 和 Cgroups 技术实现进程、网络、文件系统的资源的隔离与限制。 2.3、标签（Tag） 标签用于标识镜像的特定版本或变体。一个镜像可以有多个标签，但它们可能指向同一个镜像 ID（即内容相同）。 如果不指定标签，默认使用 latest 注意：latest 并不一定代表“最新稳定版”，它只是一个约定俗成的标签，实际含义由镜像维护者决定。 2.4、仓库（Repository）与注册中心（Registry） 仓库（Repository）：存储同一软件不同标签（版本）镜像的集合。例如 library/nginx 是 Docker Hub 上 nginx 的官方仓库。 注册中心（Registry）：存放多个仓库的服务。最常见的是 Docker Hub，也可以搭建私有 Registry（如 Harbor、GitLab Container Registry）。 示例完整镜像名： docker.io/library/nginx:1.25 其中： docker.io：Registry 地址（默认可省略） library：命名空间（官方镜像通常省略为 nginx） nginx：仓库名 1.25：标签 二、命令 2.1、镜像管理 Dockerhub 地址：Docker Hub Container Image Library | App Containerization 国内镜像： 从 Dockerfile 构建镜像： 参数： -t 指定镜像标签 --file 指定 Dockerfile 路径，不存在此参数时默认从当前路径下构建 docker build -t <tag> ./ 从远程仓库拉取某个镜像： 镜像标签 <tag> 可省略，默认使用 latest docker pull <image><:tag> 如果没有配置镜像源只是想要临时通过某个（docker.xuanyuan.me）镜像源拉去镜像： docker pull docker.xuanyuan.me/<image><:tag> 将本地镜像推送到远程仓库 docker push <image> 列出本地所有镜像 参数： -a 查看所有镜像 -q 只显示镜像 ID docker image list # 等价于： docker image ls # 等价于： docker images 列出与关键词匹配的本地镜像 docker image list <关键词> # 等价于： docker image ls <关键词> # 等价于： docker images <关键词> 查看镜像的详细信息（以 JSON 格式输出） docker image inspect <image> 查看镜像的分层历史（各层的创建指令和大小） docker image history <image> 删除本地镜像文件 参数： -f 强制删除 -a 删除所有未使用镜像 <image> 可以是文件名，也可以是镜像 ID docker image rm <image> # 简写： docker rmi <image> 注意：当存在依赖于该镜像创建的容器时，镜像文件默认是无法被删除的。尽管可以使用 -f 参数来强制删除一个存在容器依赖的镜像，但并不推荐。正确的做法是，先删除依赖该镜像的所有容器之后再删除镜像。 删除所有悬空镜像 悬空镜像：Dangling Images，即没有标签且未被容器引用的镜像，通常出现在重新构建同名镜像后，旧镜像失去标签但仍存在） docker image prune 删除所有未被任何容器使用的镜像 docker image prune -a 将镜像保存为 tar 文件（一般用于离线迁移） docker save -o <file.tar> <image> 从 tar 文件加载镜像到本地 docker load -i <file.tar> 给镜像打标签： docker tag <image> <tag>qq 2.2、容器启停 Docker 运行容器前需要本地存在对应的镜像（Image）， 如果本地不存在该镜像，Docker 会尝试从配置文件（/etc/docker/daemon.json）的注册中心中下载。 创建并启动容器 参数： -d 后台运行 -it 交互式终端 --name 指定容器名 -p host:container，端口映射 -v /host:/container，卷挂载 --restart 重启策略 docker run [OPTIONS] <image> 例如： docker run -d --name nginx-app-test -p 8080:80 nginx 只创建容器，不启动 参数： --name 容器名 -v 卷挂载 docker create -i <container> --name <name> 启动已经创建的容器： 参数：-i 交互式启动 docker start -i <container> 在运行的容器中执行命令 参数： -it 交互式终端 docker exec -it <container> <command> 停止运行中的容器： 优雅停止容器，会向容器发送 SIGTERM，等待退出 参数：-t 停止等待时间（单位为秒） docker stop -t 强制停止容器： 会向容器发送 SIGKILL。同Linux的kill -9 docker kill <container> 重启容器： 参数：-t 停止等待时间（单位为秒） docker restart <container> 2.3、容器管理 查看运行中的容器 参数： -a 查看所有容器 -q 只显示容器ID docker ps # 等价于： docker container ls 删除已停止的容器 docker rm <container> 若要删除的容器仍在运行，需加上参数 -f： docker rm -f <container> 删除所有已停止容器 docker container prune 查看容器的标准输出和错误日志： 参数： -f 跟踪日志 --tail <n> 显示最后 n 行 docker logs <container> 查看容器内运行的进程 docker top <container> 试试监控容器的 CPU、内存、网络等资源使用情况 docker stats <container> 在主机与容器之间复制文件 docker cp ... 从主机复制文件到容器： docker cp <主机路径> <容器名或ID>:<容器内路径> # 例如： docker cp ./app.conf myapp:/etc/app.conf 从容器复制文件到主机： docker cp <容器名或ID>:<容器内路径> <主机路径> # 例如： docker cp myapp:/var/log/app.log ./ 导出容器为 tar 文件： 参数：-o 指定输出文件名 docker export <container> -o <file.tar> 从 tar 文件导入为镜像： docker import <file.tar> 2.4、标签管理 给镜像打标签： docker tag <image> <tag> 删除特定标签： docker rmi <image>:<tag> 参考文档： Docker - 马燕龙个人博客 云服务器 搭建 Docker_腾讯云 Docker 教程 | 菜鸟教程
关于华为悦盒EC6108V9的一种比较另类的救砖方法
目录： 一、前期准备 1.1、USB转TTL模块 1.2、主板上焊接针脚 二、HiTool 线刷 2.1、跑码 2.2、开始刷机 2.3、系统启动 三、破解 四、后续 五、碰到的坑 5.1、关于在刷机前配置板端ip的问题 5.2、发送数据帧失败，请检查串口连接是否正常 我手上的这个电视盒子，是2016 年家里办宽带的时候电信送的，在 2020 年疫情期间被我刷机给变砖了 :@(狂汗) 。盒子接上电源开机的时候电视完全没有反应，左边绿灯与中间红灯常亮，Recovery 进不去，使用遥控器也没有任何反应。当时还抱着卡刷救砖的希望，尝试了网上说的短接 J15 针脚强制刷机，结果一点用也没有，然后淘宝又买了 TTL 转 USB 模块准备线刷救砖，买来还没操作就被网上那些教程吓住了，再加上那段时间打游戏也打的火热，这个事也就被无限期搁置了（拖延症晚期患者 ::(酸爽) ）。后来直接就买了斐讯 N1，转 N1 的阵营了，一直用到了现在。直到前两天在 B 站刷到这个将华为悦盒刷成 Ubuntu 服务器的视频： {bilibili bvid="BV1Y3411V77b" page=""/} 这个视频让我又有了天晴了雨停了我又觉得我行了的感觉，正好这几天毕业答辩的事也忙完闲下来了，所以花了一（亿）点点时间做一下最后救砖的尝试，当然最后算是成功了，所以写这篇博客来记录一下，为同样变砖的同志提供一个救砖的参考方法。 事先在此说明：这是在华为悦盒使用卡刷、强制卡刷都没有办法救砖时，并且还找不到更适配的固件的情况下，我摸索出来的一个比较另类的救砖方法，目前这个方法只在我的这个盒子上成功了，其他的盒子还没有试过（也没有条件尝试），因此并不能保证这个方法的通用性。在 ZNDS 论坛上有个类似的方式是这个（不过我并没有尝试成功）。 如果你是老司机了，那么本文救砖的方式可以试一试，救砖成功那么恭喜你，如果尝试多次还不成功的话那建议再去找找别的方式，相反如果你此前没有过刷机的经验或者经验不足，且无法独立解决报错问题，那么强烈建议慎用本文所提供的方法！！ 在刷机过程中造成的损坏恕博主不能负责！！！ 在刷机过程中造成的损坏恕博主不能负责！！！ 在刷机过程中造成的损坏恕博主不能负责！！！ 首先说明一下我手上这个盒子的型号规格：型号为华为悦盒 EC6108V9，用的 CPU 型号是 Hi3798MV100，存储规格为 1G + 4G。 型号信息： 主板布局： 一、前期准备 1.1、USB转TTL模块 线刷需要 USB 转 TTL 模块，淘宝几块钱就能买到还送杜邦线，就是这玩意： 无脑买型号是 CH340 的就行，看网上说大部分 CH340 免驱动，但是我手上这个不是，所以建议到时候跟卖家问清楚再买。甚至只要你愿意多花几块钱，还可以买到土豪金配色的（刷机时有神秘 buff 加成 :@(吐舌) ）。 刷机之前检验一下 TTL 模块是否需要驱动，模块插到电脑上之后，在设备管理器 -> 端口选项下面会显示硬件名称跟端口： 如果不显示的话应该是没有驱动，打开 Win10 更新 -> 检查更新，有更新的话就点击安装就行： 1.2、主板上焊接针脚 此外还需要在电视盒子主板的 GND、RX、TX 这三个脚位上焊接三个排针，方便用杜邦线连接 TTL 模块，最后效果是这样： 需要注意的是盒子主板与 TTL 模块针脚连接的对应关系：模块的 GND 脚连接主板的 GND 脚，模块的 RX 与 TX 与主板要反着连，即模块的 RX 连接主板的 TX，TX 连接主板的 RX。 二、HiTool 线刷 线刷工具用到 HiTool，下载地址放在文末。这个软件需要 Java 环境，如果打开报错的话就配置一下 Java 环境，配置方法参考这篇博客：Win10系统配置Java开发环境 - Roookie博客 | 记录 · 收纳 · 分享 (wlplove.com)。 软件启动之后，首先要选择芯片平台，我选择了“Hi3798MV100”，然后进入软件，打开 “HiBurn”模块，这就是线刷需要用到的功能。 2.1、跑码 开始刷机前，简单介绍一下“跑码”。 这个操作在刷机失败之后查找错误原因是非常有用的。我刚开始查资料时看到网上很多人都提到了“跑码”这个词，弄得我一脸懵逼，不过跟着操作了以后就大概理解什么意思了，简单来说，跑码会在硬件启动过程中输出硬件信息、一些提示信息，也会在出现错误的时候输出错误代码，对定位硬件启动的错误有很大的帮助。 在软件菜单栏上点击这个图标打开终端窗口： 在打开的终端窗口上前三个按钮的功能分别是连接、断开连接、设置： 连接前先点击设置按钮配置一下连接端口，端口就是前面设备管理器里显示的 TTL 模块的端口： 设置完成之后，点击连接按钮，然后给盒子通电，首先会在终端输出当前设备的硬件信息，然后盒子会尝试启动系统，同时在终端输出启动过程中的提示信息，比如刚开始我的盒子就是一直循环输出同一段报错信息： 看报错信息应该是在尝试启动的过程中卡在了 fastboot 上。 2.2、开始刷机 相关文件链接已放在文末。 给盒子断电并连接网线，在软件里配置本机与盒子的 IP 地址： 串口：设备管理器里显示的 TTL 模块的连接端口 服务器 IP：本机的 IP 地址 IP 地址：网络盒子的 IP，可以不用改 网关：路由器的 IP 然后找到下方的“烧写eMMC”： 选择刷机文件目录下面的 “xml” 分区表文件，下方表格中就会自动导入相关的分区镜像，选择要刷入的分区文件，点击烧写，当下面控制台出来提示以后给盒子通电，然后等着刷机完成就行了。 这就是整个刷机步骤，很简单吧？ ::(呵呵) 但是吧，实操就不是这样了，因为适配的线刷固件是个大问题。 我找了不少的搜索引擎、论坛、网盘，只找到了几个 CA 版四川电信的盒子线刷固件，并且都是适配 8G 版本的华为悦盒，对比了一下文件结构和大小，最后发现有好几个是同一份文件 ::(挖鼻) ，其他还找到了很多诸如“update.zip”的这类卡刷包以及线刷的 fastboot、recovery 等文件，然而卡刷包对于线刷并没有什么卵用。 鉴于找不到完全适配的线刷固件，所以只能凑活用这个四川电信的 CA 固件了。刚开始我还没有什么思路，我就抱着死马当活马医的心态想着给盒子刷这个固件试试，看能不能刷进去。 点击“刷写”不到一分钟，不出意外地控制台就报错了： 第一点提示说是“烧写的 Fastboot 镜像与当前单板型号或 Flash 不匹配导致”，那就可能是 fastboot 文件的问题？此时我灵机一动，正好有之前下载到的适配我这个盒子的 fastboot 文件啊，于是我就用下载到的 fastboot 文件替换了刷机固件下的 fastboot 文件，然后继续刷机。 果然，这下子没有报错，显示开始刷机了，刷的时间比较长，四十几分钟后提示烧写完成： 2.3、系统启动 我一下来了精神，没想到瞎猫碰到死耗子，竟然真就给刷进去了。我连忙给盒子接到电视上，找出吃灰了两年的遥控器，塞两节电池之后开始开机，果然就见到了那个熟悉的界面： 接下来系统开始进行初始化走进度条，就在我以为救砖成功的时候，进度条卡在了 50% 不动弹了，提示“接入网络故障”： 可问题是我已经给盒子插了网线了啊，莫非是要连接光猫上的“iTV”接口？试了连接到光猫上的网口还是卡在这里，我想着要不然恢复一遍出厂设置吧，结果恢复完之后提示信息又变成“通路故障或AAA认证失败”了： 行吧，虽然依然没进去系统，至少比变砖强点。 这时候想起网上不少的刷机教程，都提到了卡刷这个方式，于是我也下了好几个卡刷包想着试一试卡刷，将刷机文件在硬盘根目录与“upgrade”文件夹各放了一份，开机通过电源键进入 Recovery，选择 “Apply update from external storage（从外部存储更新）”选项卡刷，但是要么直接提示“更新失败”，要么就是好不容易开始更新了，结果一会之后卡进度条还是提示更新失败。 起初我还怀疑是不是刷机包给下错了，但我试了好几个之后都不行之后就大概确定不是了，再尝试了一下短接 J15 针脚强刷，依然没有任何反应，卡在这了。 后面看到这一篇帖子华为悦盒通用刷机救砖破解教程_华为悦盒/华为盒子 ROM固件_小白刷机网 (xiaobaishuaji.com)中提到的更新了签名会导致卡刷失败，按这里面提到的方式刷机前进行一次“三清”，这不清不重要，清完之后启动的时候结果直接变砖无法启动 :@(喷血) ，.......无奈。 三、破解 在这个界面卡了好长时间，结果发现其实按遥控器上的设置建是可以进入设置菜单的，但需要操作码，网上查了一下，我用“6321”进去了。 操作码大概可能有这么多个：一般是运营商客服电话（10000、10086、10010），除此之外还有：8288、6321、2878、3008、8005、1301、123456等，都没有用的话，可以试试专家模式密码189189 来自：华为悦盒ec6108v9高级设置操作码常用汇总 到设置界面看了一下设备信息，我大概知道为什么卡刷失败了，因为这个盒子从 pub 版本被刷成 CA 版的了： 到这里的话，我对卡刷是不报什么希望了。但是好在盒子已经能启动了，虽然还没办法通过系统自带的 IPTV 是进入桌面，但是能进设置界面啊，那就存在破解安装当贝桌面的可能性，然后绕过 IPTV 进入系统当贝桌面。 关于破解华为悦盒安装第三方桌面的步骤，在 ZNDS 论坛的这篇帖子 最新华为悦盒V9_V9U_V9E_V9A_V8通用傻瓜式刷机包！_华为悦盒_ZNDS 里已经写挺详细的，我就懒得写了，直接参考这篇帖子就可以。破解工具在文末。 接下来就比较顺了，破解果然是可以的，破解重启之后就有选择桌面的弹窗了： 四、后续 破解完成之后，安装了几个软件用了一会，体验吧只能说很一般，目前主流的视频软件操作起来卡卡的，盒子发热还比较严重（虽然不摸是感觉不出来的），并且遥控器上的首页按键是没有响应的（估计可能是固件问题）。当然还是不能用太高的要求来评价它，毕竟盒子是七八年前了，实在太老了，就连 CPU 还是 32 位，性能放在今天来看实在是有点捉急。综合来说，安装一个直播软件来看电视直播是比较好的选择。 到这我就准备要收拾家伙事儿不搞了，然后我就在网上又发现了一个线刷固件，适用于 8G 版本盒子，我想着最后尝试一下吧，下载替换 fastboot 文件一气呵成，刷固件依然花了四十多分钟。启动之后还是卡在了运营商自带的 IPTV 界面，进入设置界面查看设备信息之后，发现这个固件是浙江的移动百盒固件，不过是 PUB 版本的，还行，比之前的那个 CA 固件强，用卡刷的方式尝试了一下刷第三方系统，是可以正常刷第三方系统的。因此把这个固件下载链接也放在了文末，有需要的话用这个也行。 最后用卡刷的方式刷入电信的原厂固件，再破解就行了，本来想着还能再认证一下使用 IPTV 来看电视的，但是我尝试之后发现这边的 IPTV 认证地址竟然都挂了，所以就干脆放弃了。 五、碰到的坑 这里记录几个我在刷机过程中碰到的问题，以供参考。碰到问题与报错不要怕，仔细查看分析控制台输出与报错，多猜多尝试。 5.1、关于在刷机前配置板端ip的问题 刚开始我并没有注意到这个问题，所以开始刷机时都是报错： 第一次我还不信邪，多尝试了几次之后我就意识到了问题：我的电视盒子都开不了机了，连接到网线之后路由器后台根本识别不到这个设备，那么现在设置的 IP 地址肯定是无效的呀。 这就是我碰到的第一个大坑，研究了一会我的解决办法是，给家里吃灰的一个旧路由器插上电，用这个路由器来组网，这个局域网里面就只有盒子和笔记本两台设备，修改 HiToll 设置里的 IP 地址，板端 IP 同样随便设置（不能跟笔记本 IP 重复），这下刷机就可以了。 所以关于这个问题我的猜测是这样的（计算机网络学的不好，猜错了大佬轻喷 ::(小红脸) ）：当局域网中设备比较多的时候，笔记本将刷机数据通过路由器给下一个结点传输的时候，设备太多就导致无法确定目标传输设备，所以就会连接超时报错，相反如果只有两个设备的话，路由器传输数据时不是传输给盒子就是传输给笔记本，传输给笔记本应该是不太可能，所以就只能将数据传输给另一设备，这么阴差阳错地就完成了传输。 怎么莫名有种玄学的感觉？？ ::(笑尿) 5.2、发送数据帧失败，请检查串口连接是否正常 刚点击刷写以后，控制这样报错： 以我的情况来看，是 fastboot 文件没有选对，换了适配设备的 fastboot 文件就不报错了。 文末再放上几个刷机查资料过程中发现的几个有用的帖子吧，供有需要的参考： 海思hi3798mv100机型通用twrp_华为悦盒_ZNDS 华为悦盒怎么进入REC模式升级双清恢复出厂设置最全方法_华为悦盒_ZNDS 河南移动cmcc-2 ch电视盒子Hi3798MV310线刷-卡刷-刷机-救砖 - 知乎 (zhihu.com) ec6108v9c刷回安卓看电视 - 海思机顶盒NAS社区 (histb.com) 关于hitool刷写... - 海思机顶盒NAS社区 (histb.com) 华为悦盒EC6108V9 CA高安版1+4G电信4K机顶盒拆机救砖文件TTL线刷 | 西安艾金达贸易有限公司 (aijinda.cn) 华为 悦盒EC6108V9_PUB-8G内存版线刷救砖软件下载_怎么安装第三方软件_应用APP下载_沙发管家 (shafa.com) 【已解决】 EC6108V9 等待boot启动超时，单板上无fastboot或当..._华为悦盒_ZNDS 文件下载链接： https://pan.baidu.com/s/1OZdZQRhWsE49pto_oAzbwQ?pwd=xy6m 提取码: xy6m
记录一下写论文过程中新学会的一些Word使用技巧
目录： 一、设置子标题 二、在不同的页设置不同的页眉/页码/页脚 三、添加的图片只占一行位置，无法完全显示出来 四、将文章中的英文、数字的字体格式一键设置为Times New Roman 五、在文档任意一个位置上开始之前的编号 六、快捷键： 七、绘制三线表 一、设置子标题 选中要设置为标题的行 开始 -> 段落上面找到多级标题的图标： 选择一个设置的多级标题样式： 就出现了标题，然后更改标题级别使其成为子标题： 此时标题编号可能不是我们想要的，所以还需要调整一下标题编号： 标题更改成功： 二、在不同的页设置不同的页眉/页码/页脚 在需要页眉/页码/页脚页码的页上第一行文字前（或是上一页的最后一行）添加分页符（布局-> 分隔符 -> 下一页）： 插入页眉/页码/页脚，此时插入的页眉/页码/页脚将以这个分页符为分界被分成了两部分，选中前面不用的页眉/页码/页脚，取消这个选项（引用 -> 链接到前一条页眉/页脚）： 接下来删除不用的页眉/页码/页脚即可，还有多出来的分页符 三、添加的图片只占一行位置，无法完全显示出来 就像这样： 方框为图片实际占的位置，但显示效果上只占了一行，图片不能全部显示出来 原因：图片的段落格式中设置了行距为“固定值” 解决办法：选中图片，在段落格式设置中把行距设置为单倍行距就可以解决问题 四、将文章中的英文、数字的字体格式一键设置为Times New Roman ctrl + A 选中全文，在字体设置中分别设置中文字体与英文字体的格式即可 还有个简单粗暴的方法，选中全文将全部字体设置为Times New Roman即可，中文不会受到影响。 五、在文档任意一个位置上开始之前的编号 先将这个编号的样式设置成与上一个编号相同的样式与级别 右键 -> 设置编号值（光标要放在标题一行或者选中标题），选择“继续上一列表”，填写需要开始的编号 六、快捷键： 格式刷： ctrl + Shift + C 复制格式 ctrl + Shift + V 粘贴格式 重复上一次操作：F4 七、绘制三线表 选中整个表格，右键 -> 表格属性 -> 边框和底纹 只保留表格的上下框线，并设置其宽度为 0.75 磅 再选中表格的第一行，右键设置其下框线即可：
目录 一、Spring Boot简介 二、Spring Boot的主要特性 2.1、自动配置 2.2、起步依赖（Starters） 2.3、简化配置 2.4、内置服务器 2.5、无代码生成与 XML 配置 三、Spring Boot的配置 3.1、配置文件类型 3.1.1、application.properties 3.1.2、application.yaml（或.yml） 3.2、配置优先级 3.2.1、配置文件位置的优先级 3.2.2、配置文件格式的优先级 3.3、读取配置文件的方式 3.3.1、使用@Value注解 3.3.2、使用Environment对象 3.3.3、将部分配置封装成实体类 3.4、多环境开发时配置文件的切换 3.5、yml配置文件示例 四、整合MyBatis 4.1、添加起步依赖 4.2、添加配置 4.3、扫描Mapper接口 五、使用Maven打包Spring Boot项目 一、Spring Boot简介 Spring Boot 是 Spring 框架的一个扩展，旨在简化 Spring 应用的初始搭建和开发过程。它通过自动配置和约定优于配置的原则，提供一个开箱即用的应用程序架构，能够快速构建独立运行的 Spring 应用，开发者基于 Spring Boot 的预置结构继续开发，省时省力。 Spring Boot 官方文档：https://docs.spring.io/spring-boot/index.html Spring 中文网翻译的 Spring Boot 中文文档：https://springdoc.cn/spring-boot 通过 IDEA 创建 Spring Boot 项目： 添加核心依赖 Spring Web： 除了用 IDEA 创建 Spring Boot 项目，也可以直接访问 Spring Boot 项目生成网站，设定项目的元数据（如项目类型、语言、Spring Boot 版本等）之后，创建好的项目就会以压缩包的格式下载到本地，解压导入到开发工具即可。 Spring Boot 项目生成网站： https://start.spring.io/：Spring Boot 官方的项目生成工具，Java 版本和 Spring Boot 版本都比较新，国内有可能访问不了或访问速度比较慢 https://start.springboot.io/：官方项目生成工具的国内镜像，Java 版本和 Spring Boot 版本与官网一致，国内都能访问 https://start.aliyun.com/：从域名能看出来是阿里云镜像，国内都能访问，而且能用旧的 Java 版本和 Spring Boot 版本生成项目 一个典型的 Spring Boot 项目结构如下： SpringBoot-project/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── MyApplication.java │ │ └── resources/ │ │ ├── application.properties │ │ └── static/ │ │ └── templates/ │ └── test/ │ └── java/ │ └── com/ │ └── example/ │ └── MyApplicationTests.java ├── pom.xml └── README.md MyApplication.java：Spring Boot 应用的主类，使用 @SpringBootApplication 注解标记。 application.properties：Spring Boot 应用的配置文件，可以配置各种属性。 static/：存放静态资源文件，例如 HTML、CSS、JavaScript 文件等。 templates/：存放模板文件，例如 Thymeleaf、Freemarker 等。 二、Spring Boot的主要特性 2.1、自动配置 开发者无需手动配置大量 XML 或注解，Spring Boot 能够根据项目中添加的依赖，自动为应用程序生成合理的默认配置，减少手动配置。例如，在项目中添加了 spring-boot-starter-web 依赖，Spring Boot 会自动配置嵌入式的 Tomcat 服务器，并为 Spring MVC 设置好必要的组件，如 DispatcherServlet 等，无需开发者手动编写大量的配置代码。 2.2、起步依赖（Starters） 起步依赖是指对常用库和框架的依赖声明的集合，使用起步依赖可以一次性地添加相关的依赖和配置到项目中，大大简化了项目的依赖管理，减少因依赖冲突而导致的问题。 比如，spring-boot-starter-data-jpa 包含了使用 Spring Data JPA 进行数据库操作所需的所有依赖，包括 Hibernate、Spring Data JPA 和数据库连接池等。 2.3、简化配置 Spring Boot 使用 application.properties 或 application.yml 作为统一的配置文件，将应用程序的各种配置集中管理，并且提供默认配置，尽量减少开发者的手动配置。这些配置文件放置在项目的类路径下，Spring Boot 会自动加载并应用其中的配置。 并且 Spring Boot 支持多环境配置，允许开发者根据不同的运行环境（如开发、测试、生产）使用不同的配置文件。通过在配置文件名中使用 {profile} 占位符，如 application-dev.yml、application-prod.yml，并在 application.yml 中指定 spring.profiles.active 属性来激活相应的环境配置。 2.4、内置服务器 Spring Boot 支持嵌入式的服务器，如 Tomcat、Jetty 和 Undertow 等，开发者可以将应用程序打包成一个可执行的 JAR 文件，使用 java -jar 命令可启动服务，无需单独部署到外部的应用服务器上。 例如，在开发 Web 应用时，只需在 pom.xml 文件中添加 spring-boot-starter-web 依赖，Spring Boot 会自动配置并启动一个嵌入式的 Tomcat 服务器，让开发者可以快速进行开发和测试。 2.5、无代码生成与 XML 配置 Spring Boot 无需代码生成和 XML 配置，完全基于注解和 Java 配置。 三、Spring Boot的配置 3.1、配置文件类型 Spring Boot 支持两种主要的配置文件类型：application.properties 和 application.yaml（.yml）。 3.1.1、application.properties 这是传统的 Java 配置文件格式，每行定义一个属性，采用 key=value 的形式。例如： server.port=8080 spring.datasource.url=jdbc:mysql://localhost:3306/spring_db spring.datasource.username=root spring.datasource.password=password 3.1.2、application.yaml（或.yml） YAML（YAML Ain't Markup Language）是一种人类可读的数据序列化格式，它的特点包括： 使用缩进（空格数不限）表示层级关系（必须用空格缩进，不能使用 Tab） 使用 key: value 的形式表示键值对 支持列表、嵌套结构等复杂数据类型 例如： server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: password 关于 .yaml 和 .yml 的区别： 在 Spring Boot 项目中，YAML 文件通常以 .yaml 或 .yml 作为文件扩展名。 这两种扩展名本质上是相同的，它们都表示 YAML 格式的文件。.yaml 是 YAML 文件的官方推荐扩展名，而 .yml 是 .yaml 的简写形式。在功能上两者完全等价，Spring Boot 对它们的解析方式没有任何区别，无论使用 .yaml 还是 .yml，Spring Boot 都能正确加载和解析配置文件。 如果同时存在 application.yaml 和 application.yml，Spring Boot 会优先加载 application.yml。 3.2、配置优先级 3.2.1、配置文件位置的优先级 优先级最高的配置是命令行参数，通过命令行传递的这个参数将会覆盖原配置： java -jar app.jar --server.port=9999 不同位置配置文件的优先级分别为： 项目根目录下的 /config 子目录中的配置文件 项目根目录中的配置文件 类路径下的 /config 包中的配置文件 类路径根目录中的配置文件 3.2.2、配置文件格式的优先级 如果在同一个目录下同时存在 application.properties、application.yml、application.yaml 这几个文件，那么 Spring Boot 对配置文件的加载优先级为： application.properties > application.yml > application.yaml 3.3、读取配置文件的方式 假设在 YAML 配置文件中存在如下配置： server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/spring_db?useSSL=false&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver userInfo: name: 张三 age: 30 likes: - 游戏 - 健身 - 读书 3.3.1、使用@Value注解 @Value 注解可以直接将配置文件中的单个属性值注入到类的字段中。 @Component public class ConfiurationBean { // 简单属性 @Value("${spring.datasource.url}") private String url; // 数组 @Value("${userInfo.likes}") private String[] likes; // 数组里的其中一个属性 @Value("${userInfo.likes[1]}") private String like; // ... } 3.3.2、使用Environment对象 在 Spring Boot 中，Environment（org.springframework.core.env.Environment）是一个用于管理应用程序运行时环境配置信息的接口，它可以使开发者方便地获取和使用项目的配置参数，无论是来自 application.properties、application.yml 文件，还是系统环境变量、命令行参数等。 在需要使用 Environment 对象的类中，可以使用 @Autowired 注解将 Environment 对象自动注入进来，然后在类的方法中使用 getProperty() 方法获取配置信息。 @Component public class ConfiurationBean { @Autowired private Environment env; public void printProperty() { // 获取并使用属性 String port = env.getProperty("server.port"); System.out.println(port); } } 3.3.3、将部分配置封装成实体类 创建一个 Java 实体类，属性与配置项一一对应，使用 @ConfigurationProperties 注解将配置文件中的属性绑定到该 Java 对象上： @Component @ConfigurationProperties(prefix = "userInfo") public class UserInfo() { private String name; private int age; private String[] likes; // get方法、set方法、构造方法 } 3.4、多环境开发时配置文件的切换 在项目的开发中，常常需要在多个环境（开发环境 dev、生产环境 prod 等）部署项目，并且每个环境的配置可能都不太一样（如日志等级、数据库属性等），因此每个环境都有单独的一个配置文件。 Spring Boot 支持根据不同的环境加载不同的配置文件，常用的做法是建一个公共配置文件 application.properties 或 application.yml 来存放每个环境中相同的配置，再给每一个环境建一个单独的配置文件存放个性化配置，该配置文件的命名规则为 application-{profile}.properties 或 application-{profile}.yml。 例如开发环境的配置文件为 application-dev.yml，生产环境的配置文件为 application-prod.yml，则在公共配置文件 application.yml 中激活指定配置文件的方式为： spring: profiles: active: dev 也可以在启动项目 JAR 文件时通过命令行参数 spring.profiles.active 指定： java -jar app.jar --spring.profiles.active=dev 如果既在公共配置文件 application.yml/application.properties 中指定了激活哪个配置文件，又通过命令行参数指定，则最后生效的是命令行参数，因为命令行参数的优先级最高。 在 IDEA 中也可以直接指定命令行参数： 新版本 IDEA： 3.5、yml配置文件示例 server: port: 8081 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 数据源用druid type: com.alibaba.druid.pool.DruidDataSource # MyBatis配置 mybatis: # 指定Mapper XML文件的位置 mapper-locations: classpath:mapper/*.xml # 实体类的包路径 type-aliases-package: com.example.demos.web configuration: # 开启驼峰命名映射 map-underscore-to-camel-case: true # 项目日志等级 logging: level: # 全局日志等级 root: info # 设置MyBatis的日志级别为DEBUG com.example.mapper: debug org.mybatis: debug org.apache.ibatis: debug # 自定义配置 四、整合MyBatis 4.1、添加起步依赖 新版 IDEA 中可以直接在 pom.xml 文件的 <dependencies> 标签旁边点击 “Add Starters” 添加 MyBatis 与 MySql 的起步依赖： 或者手动在 pom.xml 文件中添加 MyBatis 的起步依赖与 MySQL、Druid 的依赖坐标： <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> 4.2、添加配置 然后在配置文件中添加数据源与 MyBatis 配置： spring: datasource: url: jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8&serverTimezone=UTC username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver # 使用druid数据源 type: com.alibaba.druid.pool.DruidDataSource # MyBatis配置 mybatis: # 指定Mapper XML文件的位置 mapper-locations: classpath:mapper/*.xml # 实体类的包路径 type-aliases-package: com.example.demos.web # 指定MyBatis的全局配置文件位置，可以进行更细颗粒度的MyBatis配置，不需要就不写 # config-location: classpath:mybatis-config.xml configuration: # 开启驼峰命名映射 map-underscore-to-camel-case: true # 项目日志等级 logging: level: # 全局日志等级 root: info # 设置MyBatis的日志级别为DEBUG com.example.mapper: debug org.mybatis: debug org.apache.ibatis: debug 4.3、扫描Mapper接口 最后在写接口的时候在上面用 @Mapper 注解标记一下这是 MyBatis 的 Mapper 接口： @Mapper public interface UserMapper { User select(); // ... } 或者直接在 Spring Boot 启动类上面用注解 @MapperScan() 进行全局配置扫描，指定 Mapper 接口类的包路径，Spring 会自动扫描该包下的所有接口，并将其注册为 MyBatis 的 Mapper 接口，无需在每个接口上都添加 @Mapper 注解。 @SpringBootApplication @MapperScan("com.example.mapper") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } 至此，Spring Boot 框架整合 MyBatis 框架完成。 五、使用Maven打包Spring Boot项目 在 pom.xml 文件中，确保配置了 Spring Boot Maven 插件： <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.3</version> <configuration> <mainClass>com.example.demo.DemoApplication</mainClass> <skip>false</skip> </configuration> </plugin> </plugins> </build> 在项目根目录下运行打包的命令： # 其实是两条命令，mvn clean是清除项目target目录下的文件，mvn package打包命令，两个命令一起执行。 # -Dmaven.test.skip=true表示排除测试代码之后打包 mvn clean package -Dmaven.test.skip=true 或者在 IDEA 中依次操作 clean 与 package： 打包时，一般都要先进行 clean 操作清理项目之前构建过程中生成的临时文件和输出文件，使项目恢复到初始状态，目的是确保项目不会受到之前构建结果的影响，避免旧的文件干扰新的构建过程。 打包完成后，会生成两个 JAR 文件，其中一个后缀为 .original，只包含工程中的 Class，不包含依赖；另一个后缀为 .jar 的文件是 SpringBoot 打包插件创建的，包含了应用依赖和 Spring Boot 相关的 Class，可以直接运行。生成的 JAR 文件保存在 target 目录下，文件名为 {项目名称}-{版本号}.jar。例如：demo-0.0.1-SNAPSHOT.jar 使用以下命令运行打包好的 JAR 文件： java -jar demo-0.0.1-SNAPSHOT.jar 并且可以通过命令来指定部分参数： java -jar demo-0.0.1-SNAPSHOT.jar --server.port=9999 --spring.profiles.active=prod
目录： 1、监听端口 2、日志功能 2.1、访问日志 2.2、错误日志 3、配置域名 4、静态资源 5、重定向 5.1、网站根目录重定向 5.2、特定目录重定向 6、反向代理 7、负载均衡 8、SSL配置 1、监听端口 server { # 用于HTTP协议 listen 80; # 用于HTTPS协议 listen 443 ssl; # 用于HTTP2 listen 443 ssl http2; # 使用IPv6监听80端口 listen [::]:80; # 仅使用IPv6 listen [::]:80 ipv6only=on; } 2、日志功能 Nginx的日志分为两种：access_log （访问日志）和 error_log（错误日志）。 对于日志的格式，Nginx提供了一种名为 combine 的格式，如果没有明确指定日志格式则默认使用该格式。 如果不使用 combine 格式的话，可以使用 log_format 指令来自定义，其具体用法参考Nginx日志配置详解或者官方文档：HttpLog模块-Nginx中文文档。 2.1、访问日志 访问日志主要记录客户端的请求，客户端向Nginx服务器发起的每一次请求都记录在这里。客户端IP，浏览器信息，referer，请求处理时间，请求URL等都可以在访问日志中得到。 server { # 访问日志文件的写入位置，相对或绝对路径 access_log /path/to/file.log; # 选择访问日志功能的开启(on)或关闭(off) access_log on; } 2.2、错误日志 错误日志记录服务器和请求处理过程中的错误信息。 server{ # 错误日志的写入位置 error_log logs/error.log error; # 错误日志的级别，分为 debug, info, notice, warn, error, crit, alert,emerg，其取值范围是按紧急程度从低到高排列 # 只有日志的错误级别等于或高于level指定的值才会写入错误日志中。默认值是error error_log file [level]; } 3、配置域名 server { # 监听domain.com server_name domain.com; # 监听多个域名 server_name domain.com www.domain.com; # 监听所有域名 server_name *.domain.com; # 监听所有顶级域名 server_name domain.*; # 监听未指定的主机名（比如侦听IP地址本身） server_name ""; } 4、静态资源 server { listen 80; server_name domain.com; location / { # 设置网站的根目录 root /path/to/website; } } 5、重定向 5.1、网站根目录重定向 server { listen 80; server_name www.domain.com; # 将 www.domain.com 进行301重定向，跳转至 http://domain.com$request_uri return 301 http://domain.com$request_uri; } 5.2、特定目录重定向 server { listen 80; server_name www.domain.com; # 将链接 http://www.domain.com/redirect-url 进行301重定向，跳转到http://otherdomain.com location /redirect-url { return 301 http://otherdomain.com; } } 如将 domain.com 永久重定向到 www.domain.com： server { listen 80; server_name domain.com; return 301 http://www.$host$request_uri; } 6、反向代理 反向代理 - 维基百科，自由的百科全书 (wikipedia.org) Reverse proxy - Wikipedia server { listen 80; server_name domain.com; # 对特定主机的3000端口进行反向代理 location / { proxy_pass http://0.0.0.0:3000; } } 7、负载均衡 负载均衡 - 维基百科，自由的百科全书 (wikipedia.org) Load balancing (computing) - Wikipedia upstream node_js { server 0.0.0.0:3000; server 0.0.0.0:4000; server 123.131.121.122; } server { listen 80; server_name domain.com; location / { proxy_pass http://node_js; } } 8、SSL配置 server { listen 443 ssl; server_name domain.com; ssl on; # 证书文件，格式不一定都是pem，还可能是其他格式 ssl_certificate /path/to/cert.pem; # 秘钥文件，格式不一定都是pem，还可能是其他格式 ssl_certificate_key /path/to/privatekey.pem; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_timeout 1h; ssl_session_cache shared:SSL:50m; add_header Strict-Transport-Security max-age=15768000; } # 将HTTP永久重定向到HTTPS server { listen 80; server_name domain.com; return 301 https://$host$request_uri; } 部分内容转载修改自： Nginx Cheatsheet (hashnode.dev) Nginx日志配置详解_biubiuli的博客-CSDN博客_nginx 日志配置
【踩坑实录】Github提交时出现错误：remote：Permission to xxx/test.git denied to xxx
目录： 问题再现 错误原因 解决方法 问题再现 Github 提交时出现错误，报错信息如下： remote: Permission to xxx/test.git denied to xxx. fatal: unable to access 'https://github.com/xxx/test.git/': The requested URL returned error: 403 如果再试一次，可能还会有如下报错： fatal: unable to access 'https://github.com/xxx/xxx.git/': OpenSSL SSL_read: Connection was reset, errno 10054 或者： fatal: unable to access 'https://github.com/xxx/xxx.git/': Failed to connect to github.com port 443: Timed out 错误原因 这个是由于在同一台计算机上先后使用了两个Github账号。 第一个账号进行了提交之后，这个账号的凭据信息就被保存了下来，然后切换到第二个账号进行提交时，系统依然会使用第一个账号的凭据信息进行提交，因此便会报错。 解决方法 进入控制面板，找到凭据管理器选项，选择其中的 Windows 凭据，删除已经保存的 Github 凭据： 然后再重新进行提交操作，此时会弹出Github登录窗口，重新登录之后就能成功提交了。
目录 一、SpringMVC介绍 二、映射请求路径 2.1、使用@ResquestMapping进行路径映射 2.2、@ResquestMapping的属性 2.2.1、value或path 2.2.2、method 2.2.3、params 2.2.4、headers 2.2.5、consumes 2.2.6、produces 2.3、@ResquestMapping的衍生注解 三、请求参数传递 3.1、GET/POST请求传递基础参数 3.2、传递复杂参数 3.2.1、日期类型 3.2.2、引用类型 3.2.3、数组 3.2.4、集合（List/Set/Map） 3.3、传递Json数据 四、响应 4.1、返回Json数据 4.2、封装返回结果 五、REST风格 5.1、简介 5.2、规则 5.3、相关注解 5.3.1、@RestController 5.3.2、@PathVariable 5.3.3、@RequestParam 5.3.4、@RequestBody 5.4、Rest风格开发示例 5.3.1、查询 5.3.2、新增 5.3.3、修改（更新） 5.3.4、删除 六、异常处理 6.1、自定义异常 6.2、处理异常的方式 6.2.1、使用@ControllerAdvice和@ExceptionHandler 6.2.2、实现HandlerExceptionResolver接口 七、拦截器 7.1、创建拦截器 7.2、注册和配置拦截器 7.3、执行流程和顺序 一、SpringMVC介绍 Spring MVC 是 Spring 框架中的一个模块，专门用于构建基于模型-视图-控制器（Model-View-Controller，MVC）设计模式的 Web 应用程序。 相关依赖坐标： <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.0.RELEASE</version> </dependency> 在 IDEA 中根据 “maven-archetype-webapp” 模板创建 Webapp 项目： 创建基本项目结构： 在 config 包里面新建初始化 Servlet 的配置类： public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } } 再新建 SpringMVC 配置类： @Configuration @ComponentScan("com.wlplove.controller") public class SpringMvcConfig { } 二、映射请求路径 2.1、使用@ResquestMapping进行路径映射 @RequestMapping 是 Spring MVC 中将 HTTP 请求映射到控制器方法的注解，它用于类级别或方法级别，可以根据请求的 URL、HTTP 请求方法（GET、POST 等）、请求参数、请求头等信息来匹配对应的处理逻辑。 @RequestMapping 注解应用在方法上，可以为该方法映射 URL 请求路径： public class UserController { @RequestMapping("/save") public String save() { // ... } } 也可以应用在类上，为该类中的所有方法设置基础的 URL 请求路径： @RequestMapping("/user") public class UserController { @RequestMapping("/save") public void save() { // ... } @RequestMapping("/delete") public void delete() { // ... } } 2.2、@ResquestMapping的属性 2.2.1、value或path 这两个属性作用相同，用于指定 URL 请求路径。用一个字符串映射一个路径，也可以用一个字符串数组映射多个路径。 @RequestMapping(value = "/save") @RequestMapping(path = "/save") // 映射多个路径 @RequestMapping(value = {"/save", "/saveUser"}) @RequestMapping(path = {"/save", "/saveUser"}) 一般也可以简写： @RequestMapping("/save") // 映射多个路径 @RequestMapping({"/save", "/saveUser"}) 2.2.2、method method 属性用于指定处理的 HTTP 方法。可以是一个 RequestMethod 枚举值或枚举值数组，常见的请求方法有 GET、POST、PUT、DELETE 等。 public class UserController { // save方法只处理POST和GET请求，路径为/save @RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.GET}) @ResponseBody public String save() { // ... } } 2.2.3、params 用于指定请求中必须包含的请求参数和值。可以使用一些特殊的表达式，如 paramName 表示请求中必须包含 paramName 参数；!paramName 表示请求中不能包含 paramName 参数，paramName=value 表示请求中 paramName 参数的值必须为 value。 // 请求中必须包含name参数 @RequestMapping(value = "/save", params = "name") // 请求中不能包含name参数 @RequestMapping(value = "/save", params = "!name") // 请求中name参数的值必须是123 @RequestMapping(value = "/save", params = "name=123") // 请求中name参数的值不能是123 @RequestMapping(value = "/save", params = "name!=123") 2.2.4、headers 用于指定请求中必须包含的请求头及其值，用法与 params 类似。 // 只有当请求/download路径的Accept头的值为application/pdf时，downloadPdf方法才会被调用 @RequestMapping(value = "/download", headers = "Accept=application/pdf") @ResponseBody public String downloadPdf() { // ... } 2.2.5、consumes 用于指定请求的内容类型（Content-Type），即客户端发送给服务器的数据的格式。 // uploadJson方法只处理Content-Type为application/json的请求 @RequestMapping(value = "/upload", consumes = "application/json") @ResponseBody public String uploadJson() { // ... } 2.2.6、produces 用于指定响应的内容类型（Accept），即服务器返回给客户端的数据的格式。 // getHtml方法返回的响应内容类型为text/html @RequestMapping(value = "/get", produces = "text/html") @ResponseBody public String getHtml() { return " Hello "; } 2.3、@ResquestMapping的衍生注解 为了简化代码，Spring 还提供了一些 @RequestMapping 的衍生注解，它们实际上是 @RequestMapping(method = xxx) 的特定形式： @GetMapping：等同于 @RequestMapping(method = RequestMethod.GET)，用于处理 HTTP Get 请求 @PostMapping：等同于 @RequestMapping(method = RequestMethod.POST)，用于处理 HTTP Post 请求 @PutMapping：等同于 @RequestMapping(method = RequestMethod.PUT)，用于处理 HTTP Put 请求 @DeleteMapping：等同于 @RequestMapping(method = RequestMethod.DELETE)，用于处理 HTTP Delet 请求 @PatchMapping：等同于 @RequestMapping(method = RequestMethod.PATCH)，用于处理 HTTP Patch 请求 三、请求参数传递 3.1、GET/POST请求传递基础参数 GET 请求的参数通过 URL 传递，附加在 URL 后面，形式为查询字符串（Query String），例如： http://localhost:8080/save?name=Jerry&age=13 POST 请求数据通过请求体（Request Body）传递，不会显示在 URL 中，在 Postman 中使用传递参数： 在 Java 的控制器方法中使用相同名称的形参，SpringMVC 可以自动将请求参数绑定到控制器方法中同名的形参上： @Controller public class UserController { // 如果要限制使用特定请求方法（POST/GET），将RequestMapping换成PostMapping或者GetMapping即可 @RequestMapping("/save") @ResponseBody public String save(String name, int age) { // ... } } 除此之外，SpringMVC 也支持将请求参数映射到不同名称的形参上，需要用 @RequestParam 注解指定请求参数绑定到控制器方法的哪个形参上： @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(@RequestParam("name")String userName, @RequestParam("age")int userAge) { // ... } } @RquestParam 注解的属性： value 或 name：指定请求参数的名称。如果省略，默认使用控制器方法的形参名作为参数名称。 required：指定参数是否为必填项。默认值为 true，表示请求中必须包含该参数，如果请求中缺少该参数，Spring 会抛出 MissingServletRequestParameterException。如果设置为 false，则参数可以为空。 defaultValue：指定参数的默认值。如果请求中未提供该参数，则使用该默认值。 3.2、传递复杂参数 3.2.1、日期类型 在请求中传递特定格式的日期： http://localhost:8080/save?date=2023-10-12 在控制层方法的形参前面加上 @DateTimeFormat 注解并指定日期格式，SpringMVC 就可以将同名请求参数转换为日期格式： @RequestMapping("/dateParse") @ResponseBody public String dateParse(@DateTimeFormat(pattern = "yyyy-MM-dd") Date date) { // ... } 3.2.2、引用类型 例如存在一个 User 对象，其中包含一个引用类型的成员 address： public class Address { // 省 private String province; // 市 private String city; } public class User { // 姓名 private String name; // 年龄 private String age; // 地址——引用对象 private Address address; } 控制器方法中使用 User 对象接收参数： @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(User user) { // ... } } 那么在请求中传递参数时保持参数名与控制器方法形参名相同即可（不相同时使用 @RequestParam 绑定）： GET： http://localhost:8080/save?name=Jerry&age=13&address.province=河南&address.city=开封 POST： 3.2.3、数组 控制器方法中使用数组接收参数： @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(String[] nameArray) { // ... } } 那么在请求中传递参数时都使用相同名称的参数即可： GET： http://localhost:8080/save?nameArray=Jerry&nameArray=Tom&nameArray=Mike POST： 3.2.4、集合（List/Set/Map） 控制器方法中使用集合接收参数（形参前需要加 @RequestParam 注解）： @Controller public class UserController { @RequestMapping("/save") @ResponseBody public String save(@RequestParam List<String> nameList) { // ... } } 在请求中传递参数的方式与数组相同： GET： http://localhost:8080/save?nameArray=Jerry&nameArray=Tom&nameArray=Mike POST： 3.3、传递Json数据 添加处理 Java 对象与 JSON 数据相互转换的依赖坐标： <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 在 SpringMVC 配置上添加 @EnableWebMvc 注解开启 Spring MVC 的默认配置（其中包括 Java 对象与 JSON 数据的相互转换）： @Configuration @ComponentScan("com.wlplove.controller") @EnableWebMvc public class SpringMvcConfig { // ... } 发送的 JSON 数据： { "name": "Tom", "age": 12 } 控制器方法中用集合或者对象接收时形参前加上 @RequestBody 注解将请求体中的数据绑定到控制器方法的参数上： @RequestMapping("/json") @ResponseBody public String json2Dto(@RequestBody User user) { // ... } 四、响应 4.1、返回Json数据 需要添加 Jackson 的依赖： <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 在控制器方法上使用 @ResponseBody 注解，告知 SpringMVC 将控制层方法的返回值直接写进 HTTP 响应体，而不是解析为视图。最后 SpringMVC 通过 HttpMessageConverter 接口将返回值转换为适当的格式（如 JSON、XML等）。 @RequestMapping("/returnJson") @ResponseBody public User returnJson() { User user = new User(); user.setAge(20); user.setName("QWERT"); return user; } @ResponseBody 支持的返回值类型： 基本类型（String、int、boolean 等）。 自定义对象（User、Product 等）。 集合或数组（List<User>、String[] 等）。 4.2、封装返回结果 新建一个返回结果对象： public class Result { /** 状态码 */ private Integer code; /** 返回内容 */ private String msg; /** 数据对象 */ private Object data; public Result(Integer code, Object data) { this.code = code; this.data = data; } public Result(Integer code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } // get和set方法 } 自定义返回编码： public class Code { public static final Integer OK = 000000; public static final Integer ERR =999999; // 其他编码 } 对 controller 方法的返回值都统一成这个返回对象： @Controller @RequestMapping("/users") public class UserController { @Autowired private UserMapper userMapper; @RequestMapping("/{id}") @ResponseBody public Result findById(@PathVariable Integer id) { User user = userMapper.selectById(id); Integer code = user != null ? Code.OK : Code.ERR; String msg = user != null ? "数据查询成功" : "数据查询失败"; return new Result(code, msg, user); } // ... } 五、REST风格 5.1、简介 REST（Representational State Transfer）风格是一种软件架构风格，用于设计网络应用程序，其核心概念旨在通过 HTTP 协议实现客户端与服务器之间简洁、可扩展且高效的交互。 传统风格资源描述形式： http://lcoalhost/user/getById?id=1 http://localhost/user/saveUser REST风格描述形式： http://localhost/user/1 http://localhost/user REST 风格是一种设计接口的约定方式，并非规范。 5.2、规则 REST 使用统一的接口与服务器进行交互，基于 HTTP 协议的标准方法： GET 用于获取资源 POST 用于创建资源 PUT 用于更新资源 DELETE 用于删除资源 5.3、相关注解 5.3.1、@RestController @RestController 是 Spring 4.0 引入的一个组合注解，它是 @Controller 和 @ResponseBody 的结合体。其主要作用是将一个控制器类标记为使用 REST 风格，使用 @RestController 注解的类中的所有处理方法默认都会将返回值直接写入 HTTP 响应体，以 JSON、XML 等数据格式返回，而不是返回视图进行渲染。 5.3.2、@PathVariable @PathVariable 是 Spring MVC 中用于将 URL 中的模板变量绑定到控制器方法形参上的注解。它通常用于 RESTful API 中，从 URL 路径中提取参数值。 如根据 ID 查询用户的控制器方法： @GetMapping("/users/{id}") public String findById(@PathVariable Long id) { // ... } 那么对于 GET 请求链接 http://localhost/users/123456，该控制器可以通过 @PathVariable 将 “123456” 绑定到形参 id 上。 也支持在路径中定义多个路径变量： http://localhost/users/123456/orders/987654321 在控制器方法中接收多个参数： @GetMapping("/users/{userId}/orders/{orderId}") public Order getOrder(@PathVariable Long userId, @PathVariable Long orderId) { // ... } Spring MVC 5.3 及以上版本支持可选路径变量。如果路径变量是可选的，可以设置属性 required = false： @GetMapping("/users/{id}") public User getUser(@PathVariable(required = false) Long id) { if (id == null) { // 返回所有用户 return userService.getAllUsers(); } // 返回指定id的用户 return userService.getUserById(id); } 那么： http://localhost/users id为null，返回所有用户 http://lcoalhost/users/123 返回id为123的用户 5.3.3、@RequestParam 详见 3.1。 5.3.4、@RequestBody 详见 3.3。 5.4、Rest风格开发示例 5.3.1、查询 // 查询全部 @GetMapping("/users") public xxxResponse findAll() { // ... } // 根据主键查询 @GetMapping("/users/{id}") public xxxResponse findById(@PathVariable Long id) { // ... } 5.3.2、新增 @PostMapping("/users") public xxxResponse add(@RequestBody User user) { // ... } 5.3.3、修改（更新） @PutMapping("/users") public xxxResponse update(@RequestBody User user) { //... } 5.3.4、删除 @DeleteMapping("/delete/{id}") public xxxResponse delete(@PathVariable Long id) { // ... } 六、异常处理 6.1、自定义异常 新建一个自定义异常类 BusinessException： public class BusinessException extends RuntimeException { private Integer code; public BusinessException(Integer code, String message) { super(message); this.code = code; } // get和set方法 } 自定义异常编码： public class ErrorCode { public static final Integer TIMEOUT_ERROR = 10001; // 其他异常编码 } 在业务层代码中抛出异常： throw new BusinessException(ErrorCode.TIMEOUT_ERROR, "请求超时，请稍后再试"); 6.2、处理异常的方式 6.2.1、使用@ControllerAdvice和@ExceptionHandler @ControllerAdvice 是 Spring 框架提供的一个用于定义全局异常处理、数据绑定和数据预处理等逻辑的注解。在配合标注了 @ExceptionHandler 注解的方法使用时，可以在拦截到对应的异常之后终止原 controller 方法的执行，并转入该方法执行设定好的异常处理逻辑。 在 controller 包中新建一个全局异常处理类 GlobalExceptionHandler，在类中的方法上面使用 @ExceptionHandler 注解指定这个方法要处理哪种异常： @ControllerAdvice public class GlobalExceptionHandler { // Exception是所有异常的父类，在此表示拦截到所有的异常都会进行处理 @ExceptionHandler(Exception.class) // 方法参数中加入这种异常类型的形参，就可以获取到这个异常的信息 public ResponseEntity<String> doException(Exception ex) { return new ResponseEntity<>("异常信息: " + ex.getMessage()); } // 只处理RuntimeException异常 @ExceptionHandler(RuntimeException.class) public Response<T> doRuntimeException(RuntimeException ex){ // RuntimeException异常处理逻辑 } // 只处理IOException异常 @ExceptionHandler(IOException.class) public Response<T> doIOException(IOException ex){ // IOException异常处理逻辑 } // ... } 如果在控制器中使用 Rest 风格的开发，可以使用 @RestControllerAdvice 注解，@RestControllerAdvice 是 @ControllerAdvice 和 @ResponseBody 的组合注解，类中的方法返回值会自动进行 JSON 或 XML 等格式的序列化，直接作为响应体返回给客户端。 6.2.2、实现HandlerExceptionResolver接口 HandlerExceptionResolver 是 Spring Web 框架中的一个接口，它提供了一种统一处理控制器（@Controller）中抛出的异常的机制。通过实现这个接口，开发者可以自定义异常处理逻辑，以满足不同的业务需求，比如返回特定格式的错误响应、记录异常日志等。 处理异常主要通过该接口中的 resolveException 方法实现 方法参数： HttpServletRequest request：当前请求对象，通过它可以获取请求的各种信息，如请求头、请求参数等。 HttpServletResponse response：当前响应对象，可用于设置响应头、响应状态码等。 Object handler：处理当前请求的处理器对象，通常是一个控制器方法。 Exception ex：在处理请求过程中抛出的异常对象。 方法返回值： ModelAndView 是 Spring MVC 中用于封装视图和模型数据的类。如果返回 null，表示该异常解析器没有处理该异常，Spring 将继续尝试其他的异常解析器。如果返回一个非空的 ModelAndView 对象，Spring 会根据其中的视图信息渲染相应的视图，并将模型数据传递给视图。 新建一个异常处理类 CustomExceptionResolver，用 @Component 注解声明这是一个 Spring Bean，实现 HandlerExceptionResolver 接口中的 resolveException 方法： @Component public class CustomExceptionResolver implements HandlerExceptionResolver { public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView modelAndView = new ModelAndView(); if (ex instanceof IllegalArgumentException) { modelAndView.setViewName("error/400"); // 跳转到 400 错误页面 modelAndView.addObject("errorMessage", "非法参数: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_BAD_REQUEST); } else { modelAndView.setViewName("error/500"); // 跳转到 500 错误页面 modelAndView.addObject("errorMessage", "服务器内部错误: " + ex.getMessage()); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } return modelAndView; } } 七、拦截器 在 Spring 中，拦截器是利用 AOP（面向切面编程）的思想实现的一种机制，用在请求处理的不同阶段（如请求到达 controller 方法之前、controller 方法执行之后、视图渲染之前等）执行自定义逻辑，在以下的场景中广泛使用： 权限验证：在请求到达控制器之前，检查用户是否具有访问该资源的权限，如验证用户登录状态。 日志记录：记录请求的相关信息，如请求的 URL、参数、处理时间等，方便后续的调试和监控。 性能监控：统计请求的处理时间，找出性能瓶颈。 请求参数处理：对请求参数进行统一的预处理，如编码转换、参数验证等。 7.1、创建拦截器 在 controller 包中新建一个包 interceptor，创建拦截器类 ProjectInterceptor，实现 HandlerInterceptor 接口，并用 @Component 声明为一个 bean： @Component public class ProjectInterceptor implements HandlerInterceptor { // 在控制器处理请求之前调用 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 通过handler对象经过反射可以获取到原controller方法 System.out.println("preHandle: 请求到达控制器之前"); // 可以在此处进行权限验证、日志记录等操作 // 如果返回 false，请求将被中断，不再执行postHandle与afterCompletion return true; } // 在控制器处理请求之后、视图渲染之前调用 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle: 控制器处理请求之后"); // 可以在此处修改模型数据或视图 } // 在视图渲染完成之后调用（无论请求是否成功） @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion: 视图渲染完成之后"); // 可以在此处进行资源清理、日志记录等操作 } } 7.2、注册和配置拦截器 在 config 包下新建一个配置类 SpringMvcSupport，继承 WebMvcConfigurationSupport 类，并重写 addInterceptors 方法，在这个方法中注册和配置拦截器： @Configuration public class SpringMvcSupport extends WebMvcConfigurationSupport { // 注入之前定义好的拦截器类 @Autowired private ProjectInterceptor projectInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor) // 指定要拦截的路径,可以传入多个路径 .addPathPatterns("/**") // 指定要排除的路径,可以传入多个路径 .excludePathPatterns("/login", "/register"); } } addPathPatterns 和 excludePathPatterns 方法均支持 Ant 风格的路径匹配规则，具体语法规则如下： ?：匹配单个字符。 示例：/user? 可以匹配 /user1、/userA，但不能匹配 /user12。 \*：匹配任意数量的字符（不包括路径分隔符 /）。 示例：/user/* 可以匹配 /user/123、/user/profile，但不能匹配 /user/123/address。 `\**：匹配任意数量的字符（包括路径分隔符/`）。 示例：/user/** 可以匹配 /user/123、/user/123/address。 {variable}：匹配路径变量。 示例：/user/{id} 可以匹配 /user/123，并将 123 绑定到路径变量 id 除了新建一个 SpringMvcSupport 配置类来配置拦截器的方法外，还可以让原来的 SpringMvc 配置类来实现 WebMvcConfigurer 接口中的 addInterceptors 方法，也能达到相同的效果： @Configuration @ComponentScan("com.xxx.controller") @EnableWebMvc public class SpringMvcSupport implements WebMvcConfigurer { // 注入之前定义好的拦截器类 @Autowired private ProjectInterceptor projectInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(projectInterceptor) // 指定要拦截的路径,可以传入多个路径 .addPathPatterns("/**") // 指定要排除的路径,可以传入多个路径 .excludePathPatterns("/login", "/register"); } } 7.3、执行流程和顺序 拦截器执行流程： 如果有多个拦截器，形成拦截器链，它们的执行顺序如下： preHandle：按照注册顺序依次执行，必定运行。 postHandle：按照注册顺序的逆序执行，可能不运行。 afterCompletion：按照注册顺序的逆序执行，可能不运行。 例如拦截器 A、B、C 按顺序注册： preHandle 执行顺序：A → B。 postHandle 执行顺序：B → A。 afterCompletion 执行顺序：B → A。
目录 一、创建Webapp项目 二、Spring配置类 三、数据源对象（以Druid为例） 四、整合MyBatis 4.1、数据库配置 4.2、MyBatis配置 五、整合SpringMVC 六、整合Log4j 七、整合Junit 环境说明： 数据库：MySQL 8.0 Java版本：JDK8 通过注解整合 SSM 框架流程： 创建 Web 工程 SSM 整合 Spring 框架：SpringConfig MyBatis 框架：JdbcConfig / jdbc.properties / MybatisConfig SpringMVC 框架：ServletConfig / SpringMvcConfig 一、创建Webapp项目 在 IDEA 中根据 “maven-archetype-webapp” 模板创建 Webapp 项目： 创建基本项目结构： 二、Spring配置类 引入 spring-conext 的依赖坐标： <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.25.RELEASE</version> </dependency> 创建一个 Java 类 SpringConfig 作为 Spring 配置类，类上面添加 @Configuration 注解标识这是一个配置类，添加 @ComponentScan 注解来设置扫描注解的路径 @Configuration @ComponentScan("com.xxx") /** * 如果有多个要扫描的包路径，可以用数组格式： * @ComponentScan({"com.xxx.dao","com.xxx.service"}) */ public class SpringConfig { } 三、数据源对象（以Druid为例） 导入 Druid 数据源的依赖坐标： <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> 新建一个配置数据库连接信息的类 JdbcConfig，里面引入配置文件中的数据库信息，然后用一个方法构造并返回一个 DataSource 对象，最后用 @Bean 注解设置这个方法的返回值成为 Spring IoC 容器的一个 Bean： public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 数据源Bean * @return */ @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; } } Spring 配置类 SpringConfig 中用 Import 注解引入 JdbcConfig 这个类： @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class}) public class SpringConfig { } 四、整合MyBatis 4.1、数据库配置 在 src/main/resources 目录下新建一个配置数据库连接信息的配置文件 jdbc.properties： jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=root 使用 @PropertySource 注解在 Spring 配置类 SpringConfig 上加载外部的 properties 文件： @Configuration @ComponentScan({"com.xxx"}) +@PropertySource("classpath:jdbc.properties") public class SpringConfig { } 4.2、MyBatis配置 导入 MyBatis 及 MySQL 的相关依赖坐标： <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.25.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> 新建一个 MyBatis 的配置类 MybatisConfig，配置 SqlSessionFactoryBean 和 MapperScannerConfigurer 这两个 Bean： public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setDataSource(dataSource); ssfb.setTypeAliasesPackage("com.xxx.xxx"); return ssfb; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer msc = new MapperScannerConfigurer(); // Mapper的XML映射文件所在路径 msc.setBasePackage("com.xxx.dao"); return msc; } } Spring 配置类 SpringConfig 中用 Import 注解引入 MybatisConfig 这个类： @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class, MybatisConfig.class}) @PropertySource("classpath:jdbc.properties") public class SpringConfig { } 五、整合SpringMVC 导入 SpringMVC、Servlet 与 jackson 的依赖坐标： <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.2.25.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.18.2</version> </dependency> 新建 SpringMVC 配置类 SpringMvcConfig： @Configuration @ComponentScan("com.wlplove.controller") @EnableWebMvc public class SpringMvcConfig { } 新建 Servlet 的初始化类 ServletInitializer： public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { protected Class<?>[] getRootConfigClasses() { return new Class[]{SpringConfig.class}; } protected Class<?>[] getServletConfigClasses() { return new Class[]{SpringMvcConfig.class}; } protected String[] getServletMappings() { return new String[]{"/"}; } } 六、整合Log4j 导入 Log4j 的依赖坐标： <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.23.1</version> </dependency> 在 "src/main/java/resources" 下新建一个 Log4j 的配置文件 Log4j2.xml： <?xml version="1.0" encoding="UTF-8"?> <configuration> <Appenders> <Console name="console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </Console> <!-- <File name="allLog" fileName="logs/AlliInOne.log" append="true">--> <!-- <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>--> <!-- <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{9.9.9.1}(%L) %m%n"/>--> <!-- </File>--> <RollingFile name="rollingFileInfo" fileName="logs/${date:yyyy-MM}/log-info-${date:yyyy-MM-dd}.log" filePattern="logs/${date:yyyy-MM}/log-info-%d{yyyy-MM-dd}-%i.log"> <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <loggers> <!-- level指定日志级别，从低到高的优先级： ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <Logger name="org.mybatis" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <Logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </root> </loggers> </configuration> Log4j 配置文件详解：彻底掌握Log4j2 - 蚂蚁小哥 - 博客园 修改 MyBatis 配置类中的 SqlSessionFactoryBean，设置其 Configuration 属性： public class MybatisConfig { // ... @Bean public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.xxx.xxx"); ssfb.setDataSource(dataSource); + Configuration configuration = new Configuration(); + // 修改MyBatis使用的日志框架为Log4j + configuration.setLogImpl(Log4j2Impl.class); + ssfb.setConfiguration(configuration); return ssfb; } // ... } 七、整合Junit 导入 Junit 和 Spring-test 的依赖坐标： <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> 新建一个测试类： // 在 JUnit 5 中集成 Spring 功能（如果是Junit4则换成@RunWith(SpringJunit4ClassRunner.class)） @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = SpringConfig.class) public class SpringTest { @Autowired private UserMapper userMapper; @Test public void find() { User user = userMapper.select(); } }
目录： 一、通过注解定义Bean 1.1、启用注解支持 1.2、定义Bean 1.3、@Component的派生注解 1.3.1、@Repository 1.3.2、@Service 1.3.3、@Controller 1.3.4、@Configuration 1.4、用注解代替XML配置文件 1.4.1、配置类 1.4.2、初始化IoC容器 二、通过注解使用Bean 2.1、自动装配 2.1.1、@Autowired 2.1.2、@Qualifier 2.1.3、@Resource 2.1.4、@Primary 2.1.5、@Value 2.2、读取properties文件配置 2.3、作用域 2.4、自定义Bean初始化/销毁操作 2.5、总结 三、整合框架 3.1、数据源对象（以Druid为例） 3.2、整合Mybatis 3.3、整合Log4j 3.4、整合Junit 四、Spring事务 一、通过注解定义Bean 1.1、启用注解支持 <context:annotation-config /> 若要以注解方式注入 Bean，则需要开启扫描包中的组件，并用 base-package 属性指定扫描的基本包路径： <context:component-scan base-package="com.xxx" /> 使用 <context:annotation-scan> 标签时，默认将隐式启用对注解的支持。 1.2、定义Bean 在 XML 配置中如果要将一个 Bean 交给 Spring IoC 容器管理，需要进行如下配置： <bean id="userService" class="com.wlplove.service.impl.UserServiceImpl" /> 若用注解要实现相同目的，只需要在要被管理的 Java 类上添加 @Component 注解，并在后面的括号中指定 Bean 的名称： // 注解后面的括号里是 bean 的名称 @Component("userServiceImpl") public class UserServiceImpl implements UserService { // ... } @Component 注解也可以不指定 Bean 名称，Spring 会自动为该 Bean 生成一个默认的名称，通常是类名的首字母小写形式： @Component // 可以用名称“userServiceImpl”来获取这个Bean public class UserServiceImpl implements UserService { // ... } 所以只需要在 Java 类上加入 @Component 注解，用于标识这个类是 Spring 容器中的组件（即 Bean），就可以实现与 XML 配置中的 <bean> 标签相同的作用。 1.3、@Component的派生注解 此外，Spring 还提供了 @Component 的几个派生注解：@Repository、@Service、@Controller、@Configuration，这几个注解的功能和用法与 @Component 相同，但它们在使用场景上有所不同。 1.3.1、@Repository 用于数据访问层（Dao 层）中与数据库交互的类。 Spring 会对使用 @Repository 注解的类进行特定的异常处理（将数据访问层的异常，如 SQLException 等转换为 Spring 的 DataAccessException 异常，方便统一处理和异常传播）。 @Repository public interface UserMapper { // ... } 1.3.2、@Service 用于标识业务逻辑层（Service 层）中处理核心业务逻辑的类。 使用 @Service 注解可以将一个类声明为业务逻辑组件，将其对象存入 Spring 容器中，以便在其他组件（如Controller）中通过注入该 service 类的实例来使用其业务逻辑。 @Service public class UserServiceImpl implements UserService { // ... } 1.3.3、@Controller 用于标识控制层（Controller 层）中处理响应和请求的类。 被 @Controller 标记的类实际上就是一个 Spring MVC Controller 对象，它可以处理请求，并通过 @RequestMapping 等注解将不同的请求分发到对应的方法上。 @Controller public class UserController { // ... } 1.3.4、@Configuration 用于标记替换 XML 配置文件的配置类，这个注解的用法将在 1.4 中详细说明。 1.4、用注解代替XML配置文件 Spring 支持完全去除 XML 配置文件实现纯注解开发，实现的方式就是使用一个 Java 类来代替原本的 XML 配置文件。 1.4.1、配置类 创建一个 Java 类，类上面添加 @Configuration 注解标识这是一个配置类： @Configuration public class SpringConfig { // ... } 在 XML 配置文件中会用到 <context:annotation-config base-package=""> 标签来设置扫描注解的路径，在配置类上添加 @ComponentScan 注解也可以实现相同的效果： @Configuration +@ComponentScan("com.xxx") public class SpringConfig { // ... } 如果有多个包路径，可以用数组格式： @ComponentScan({"com.xxx.dao","com.xxx.service"}) 1.4.2、初始化IoC容器 当创建出一个配置类之后，初始化 Spring IoC 容器的方式也需要改变。 原来是通过 ClassPathXmlApplicationContext 类加载 XML 配置文件初始化得到 IoC 容器： ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml"); 现在改用 AnnotationConfigApplicationContext 类来加载配置类得到 Spring IoC 容器： ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); 二、通过注解使用Bean 2.1、自动装配 2.1.1、@Autowired 在要引用的依赖上面使用 @Autowired 注解开启自动装配注入该依赖： @Service public class BookServiceImpl implements BookService { @Autowired private BookDao bookDao; public void save() { System.out.println("book service save ..."); bookDao.insert(); } } @Autowired 注解默认按照类型（byType）进行自动装配。 2.1.2、@Qualifier 如果 Spring IoC 容器中存在多个类型相同的 Bean 时，仅仅使用 @Autowired 根据类型自动装配时就导致 Spring 无法确定应该自动注入哪一个 Bean，便会抛出 NoUniqueBeanDefinitionException 异常。那么此时使用 @Qualifier 注解来指定要装配的 Bean 名称： @Repository public class BookDao1 implements BookDao { // ... } @Repository public class BookDao2 implements BookDao { // ... } @Service public class BookServiceImpl implements BookService { @Autowired // 存在两个BookDao类型的Bean，这里指定注入名称为bookDao1的Bean @Qualifier("bookDao1") private BookDao bookDao; } 需要注意的是，@Qualifier 不能单独使用，必须与 @Autowired 一起使用。因为 @Autowired 主要是根据类型进行自动装配，而 @Qualifier 则在此基础上匹配 Bean 名称，从而进行更精确的限制。 2.1.3、@Resource 还有一个与 @Autowired 类似的注解是 @Resource，默认按照名称（byName）进行自动装配，通过其 name 属性指定要注入的 Bean 名称： @Service public class BookServiceImpl implements BookService @Resource(name = "bookDao2") private BookDao bookDao; } 不像 @Autowired 是 Spring 框架提供的用于按类型（byType）自动装配的注解，@Resource 是 JavaEE 标准中（javax.annotation.Resource）提供的用于按名称（byName）自动装配的注解，并非 Spring 框架所特有的。 2.1.4、@Primary 与 @Qualifier 类似，@Primary 注解也可以用来解决当存在多个相同类型的 Bean 时应该注入哪一个 Bean 的问题。 如果 Spring IoC 容器中存在多个类型相同的 Bean，给该 Bean 上面添加 @Primary 注解，则 Spring 会优先使用标注了 @Primary 的 Bean。 2.1.5、@Value 使用 @Value 注解实现简单类型的注入： @Service public class UserServiceImpl implements UserService { @Value(30) private int age; @Value("root") private String userName; } @Value 注解除了用于给简单类型的成员注入固定的值以外，也可以用于将配置文件中的属性注入给简单类型的成员，配置文件中的属性名写在占位符 ${} 里面： @Service public class UserServiceImpl implements UserService { @Value("${user.name}") private String userName; } 2.2、读取properties文件配置 在 src/main/resources 目录下新建一个配置数据库连接信息的配置文件 jdbc.properties： jdbc.driver=com.mysql.cj.jdbc.Driver jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db?useSSL=false&setUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=root 使用 @PropertySource 注解在 Spring 配置类上加载外部的 properties 文件，在要注入值的成员上添加 @Value 注解指定注入哪个属性： /** * Spring配置类 */ @Configuration @ComponentScan({"com.xxx"}) @PropertySource("classpath:jdbc.properties") public class SpringConfig { // ... } /** * 使用属性 */ public class DataBaseConnInfo { // 注入配置文件中的属性 @Value("${jdbc.driverName}") private String driverName; @Value("${jdbc.url}") private String url; } 若要加载多个配置文件应使用数组： @PropertySource({"classpath:jdbc.properties","classpath:appConfig.properties"}) 2.3、作用域 使用注解 @Scope 定义 Bean 的作用域是 prototype（原型/非单例）或者 singleton（单例）。 public class AppConfig { @Bean // @Scope("prototype") @Scope("singleton") public MyBean myBean() { return new MyBean(); } } 2.4、自定义Bean初始化/销毁操作 使用 @PostConstruct 注解定义初始化方法（方法名不限），将在构造方法之后执行该方法。 使用 @PreDestroy 注解定义销毁方法（方法名不限），在容器销毁前执行该方法，一般用来释放占用的资源等。 public class UserServiceImpl implements UserService { @PostConstruct publid void init() { System.out.println("init ...."); } @PreDestroy public void destory() { System.out.println("destory ..."); } } 2.5、总结 三、整合框架 3.1、数据源对象（以Druid为例） 导入 Druid 数据源的依赖坐标： <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.22</version> </dependency> 新建一个配置数据库连接的类 JdbcConfig，里面引入配置文件中的数据库信息，然后用一个方法构造并返回一个 DataSource 对象，最后用 @Bean 注解设置这个方法的返回值成为 Spring IoC 容器的一个对象： public class JdbcConfig { @Value("${jdbc.driver}") private String driver; @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; /** * 数据源 * @return */ @Bean public DataSource dataSource() { DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driver); ds.setUrl(url); ds.setUsername(username); ds.setPassword(password); return ds; } } Spring 配置类中用 Import 注解引入 JdbcConfig 这个类： @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class}) public class SpringConfig { // ... } 3.2、整合Mybatis 导入 MyBatis 的依赖坐标： <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>6.1.4</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>3.0.3</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> 新建一个 MyBatis 配置类 MybatisConfig，配置 SqlSessionFactoryBean 和 MapperScannerConfigurer 这两个 Bean： public class MybatisConfig { @Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setDataSource(dataSource); ssfb.setTypeAliasesPackage("com.xxx.xxx"); return ssfb; } @Bean public MapperScannerConfigurer mapperScannerConfigurer() { MapperScannerConfigurer msc = new MapperScannerConfigurer(); // Mapper接口所在的包路径 msc.setBasePackage("com.xxx.mapper"); return msc; } } Spring 配置类中用 Import 注解引入 MybatisConfig 这个类： @Configuration @ComponentScan("com.xxx") +@Import({JdbcConfig.class, MybatisConfig.class}) public class SpringConfig { // ... } 3.3、整合Log4j 导入 Log4j 的依赖坐标： <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.23.1</version> </dependency> 在 "src/main/java/resources" 下新建一个 Log4j 的配置文件 Log4j2.xml： <?xml version="1.0" encoding="UTF-8"?> <configuration> <Appenders> <Console name="console" target="SYSTEM_OUT"> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> </Console> <!-- <File name="allLog" fileName="logs/AlliInOne.log" append="true">--> <!-- <ThresholdFilter level="ALL" onMatch="ACCEPT" onMismatch="DENY"/>--> <!-- <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5p %c{9.9.9.1}(%L) %m%n"/>--> <!-- </File>--> <RollingFile name="rollingFileInfo" fileName="logs/${date:yyyy-MM}/log-info-${date:yyyy-MM-dd}.log" filePattern="logs/${date:yyyy-MM}/log-info-%d{yyyy-MM-dd}-%i.log"> <ThresholdFilter level="DEBUG" onMatch="ACCEPT" onMismatch="DENY"/> <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/> <Policies> <TimeBasedTriggeringPolicy interval="1" modulate="true"/> <SizeBasedTriggeringPolicy size="10MB"/> </Policies> <DefaultRolloverStrategy max="20"/> </RollingFile> </Appenders> <loggers> <!-- level指定日志级别，从低到高的优先级： ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF --> <Logger name="org.mybatis" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <Logger name="org.springframework" level="WARN" additivity="false"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </Logger> <root level="DEBUG"> <appender-ref ref="console"/> <appender-ref ref="rollingFileInfo"/> </root> </loggers> </configuration> Log4j 配置文件详解：彻底掌握Log4j2 - 蚂蚁小哥 - 博客园 修改 Mybatis 配置类中的 SqlSessionFactoryBean，设置其 Configuration 属性： public class MybatisConfig { // ... @Bean public SqlSessionFactoryBean getSqlSessionFactory(DataSource dataSource) { SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean(); ssfb.setTypeAliasesPackage("com.xxx.xxx"); ssfb.setDataSource(dataSource); + Configuration configuration = new Configuration(); + // 修改MyBatis使用的日志框架为Log4j2 + configuration.setLogImpl(Log4j2Impl.class); + ssfb.setConfiguration(configuration); return ssfb; } // ... } 3.4、整合Junit 导入 Junit 和 spring-test 的依赖坐标： <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.10.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.10.RELEASE</version> </dependency> 新建一个测试类： // 在 JUnit 5 中集成 Spring 功能，如果是Junit4则换成@RunWith(SpringJunit4ClassRunner.class) @ExtendWith(SpringExtension.class) @ContextConfiguration(classes = SpringConfig.class) public class SpringTest { @Autowired private UserMapper userMapper; @Test public void find() { User user = userMapper.select(); } } 四、Spring事务 导入 Spring 事务的依赖坐标： <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.2.10.RELEASE</version> </dependency> 在 Spring 的配置类上添加注解 @EnableTransactionManagement 开启 Spring 的事务管理功能： @Configuration @ComponentScan("com.xxx") @Import({JdbcConfig.class, MybatisConfig.class}) +@EnableTransactionManagement public class SpringConfig { // ... } 配置类中添加 PlatformTransactionManager 这个 Bean： @Bean public PlatformTransactionManager getTransactionManager(DataSource dataSource) { DataSourceTransactionManager dstm = new DataSourceTransactionManager(); dstm.setDataSource(dataSource); return dstm; } 最后在 service 方法或类上面用 @Transactional 注解设置添加事务管理，在执行该方法或类中的方法时便会开启事务管理，如果程序执行时发生异常就回滚之前的数据库操作。 需要注意的是，当在同一类中调用有 @Transactional 注解的方法时，可能不会触发事务管理，因为它绕过了 Spring 的代理机制，解决办法是将这个方法也标记为 @Transactional。