<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>秋萤blog</title>
        <link>https://qiuyingtyan.top/</link>
        <description>Recent content on 秋萤blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>秋萤</copyright>
        <lastBuildDate>Thu, 02 Oct 2025 02:47:44 +0000</lastBuildDate><atom:link href="https://qiuyingtyan.top/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Vue为什么是js写的而不是其它语言写的？</title>
        <link>https://qiuyingtyan.top/p/vuewei-shi-me-shi-jsxie-de-er-bu-shi-qi-ta-yu-yan-xie-de/</link>
        <pubDate>Sun, 29 Jun 2025 17:28:02 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/vuewei-shi-me-shi-jsxie-de-er-bu-shi-qi-ta-yu-yan-xie-de/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/%E5%88%B0%E6%A0%B9%E7%9B%AE%E5%BD%95%E4%B8%8A%E4%BC%A0%E6%BA%90%E6%96%87%E4%BB%B6.webp" alt="Featured image of post Vue为什么是js写的而不是其它语言写的？" /&gt;&lt;p style=&#34;&#34;&gt;Vue 选择用 JavaScript 开发，而不是 Java、Python 等其他语言，核心原因与​&lt;strong&gt;​前端开发的本质需求​&lt;/strong&gt;​、​&lt;strong&gt;​JavaScript 的特性​&lt;/strong&gt;​以及​&lt;strong&gt;​前端生态的演进​&lt;/strong&gt;​密切相关。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%80%E3%80%81%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E7%9A%84%E2%80%9C%E5%AE%BF%E5%91%BD%E2%80%9D%EF%BC%9A%E5%BF%85%E9%A1%BB%E7%94%A8-javascript%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​一、前端开发的“宿命”：必须用 JavaScript​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;浏览器的核心语言是 JavaScript（简称 JS）。无论你用什么语言写前端代码（比如 Java、Python），最终都需要​&lt;strong&gt;​编译/转译成 JS​&lt;/strong&gt;​，才能在浏览器中运行。这是由浏览器的底层设计决定的——浏览器只认识 JS（和 Wasm 等少数补充技术）。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;Vue 作为一个​&lt;strong&gt;​前端框架​&lt;/strong&gt;​，本质是为浏览器服务的工具库。它的代码需要直接操作 DOM、处理浏览器事件（如点击、滚动）、调用浏览器 API（如 &lt;code&gt;fetch&lt;/code&gt;、&lt;code&gt;localStorage&lt;/code&gt;），这些都​&lt;strong&gt;​只能在 JS 环境中完成​&lt;/strong&gt;​。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：如果你用 Java 写前端框架，Java 代码必须先编译成 JS（通过工具如 GWT），但这样会失去 JS 的动态性和灵活性，而且失去了直接操作浏览器 API 的能力。因此，前端框架用 JS 是“原生适配”，其他语言需要额外转译，增加了复杂度。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%BA%8C%E3%80%81javascript-%E7%9A%84%E7%89%B9%E6%80%A7%EF%BC%9A%E5%AE%8C%E7%BE%8E%E5%A5%91%E5%90%88%E5%89%8D%E7%AB%AF%E9%9C%80%E6%B1%82%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​二、JavaScript 的特性：完美契合前端需求​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;Vue 的核心设计目标是​&lt;strong&gt;​轻量、灵活、响应式​&lt;/strong&gt;​，而 JavaScript 的特性恰好能满足这些需求：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E5%8A%A8%E6%80%81%E7%B1%BB%E5%9E%8B%E8%AF%AD%E8%A8%80%EF%BC%9A%E7%81%B5%E6%B4%BB%E9%80%82%E9%85%8D%E5%A4%8D%E6%9D%82%E5%9C%BA%E6%99%AF%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​动态类型语言：灵活适配复杂场景​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;JS 是动态类型语言（变量类型可变），适合前端开发中​&lt;strong&gt;​频繁变化的场景​&lt;/strong&gt;​（比如用户输入、动态数据渲染）。Vue 的响应式系统（&lt;code&gt;reactive&lt;/code&gt;/&lt;code&gt;ref&lt;/code&gt;）需要动态追踪数据变化，JS 的动态性让这种追踪更简单（比如通过 &lt;code&gt;Proxy&lt;/code&gt; 或 &lt;code&gt;Object.defineProperty&lt;/code&gt; 监听对象属性变化）。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;对比&lt;/em&gt;：Java 是静态类型语言，变量类型固定。如果用 Java 实现类似的响应式系统，需要额外的类型检查和反射机制，代码会更复杂，性能也可能受影响。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B%E6%94%AF%E6%8C%81%EF%BC%9A%E7%AE%80%E5%8C%96%E7%8A%B6%E6%80%81%E7%AE%A1%E7%90%86%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​函数式编程支持：简化状态管理​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;JS 支持函数式编程（如高阶函数、闭包、箭头函数），这为 Vue 的​&lt;strong&gt;​组合式 API​&lt;/strong&gt;​（&lt;code&gt;setup&lt;/code&gt; 函数、&lt;code&gt;computed&lt;/code&gt;、&lt;code&gt;watch&lt;/code&gt;）提供了天然支持。函数式编程能让状态管理更简洁（比如用 &lt;code&gt;computed&lt;/code&gt; 缓存计算结果），避免复杂的状态同步问题。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：Vue 中用 &lt;code&gt;computed&lt;/code&gt; 定义派生状态时，本质是利用 JS 的闭包和函数式特性，自动追踪依赖并缓存结果。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E5%8E%9F%E5%9E%8B%E9%93%BE%E4%B8%8E%E5%AF%B9%E8%B1%A1%E7%B3%BB%E7%BB%9F%EF%BC%9A%E5%AE%9E%E7%8E%B0%E5%93%8D%E5%BA%94%E5%BC%8F%E7%9A%84%E2%80%9C%E5%9F%BA%E7%A1%80%E8%AE%BE%E6%96%BD%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​原型链与对象系统：实现响应式的“基础设施”​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;Vue 的响应式原理（如 &lt;code&gt;reactive&lt;/code&gt;）依赖 JS 的对象系统（原型链、属性描述符）。通过修改对象的 &lt;code&gt;getter/setter&lt;/code&gt;，可以高效地追踪数据变化并触发视图更新。这种实现方式在 JS 中非常自然，而在静态语言（如 Java）中需要通过反射或字节码增强，实现成本更高。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：Vue 3 用 &lt;code&gt;Proxy&lt;/code&gt; 替代 &lt;code&gt;Object.defineProperty&lt;/code&gt; 实现响应式，正是利用了 JS 对 &lt;code&gt;Proxy&lt;/code&gt; 的原生支持，避免了旧版浏览器兼容性问题。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E2%80%8B%E2%80%8B%E7%94%9F%E6%80%81%E6%88%90%E7%86%9F%EF%BC%9A%E5%89%8D%E7%AB%AF%E5%B7%A5%E5%85%B7%E9%93%BE%E7%9A%84%E2%80%9C%E9%80%9A%E7%94%A8%E8%AF%AD%E8%A8%80%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;4. ​​生态成熟：前端工具链的“通用语言”​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;JS 拥有全球最大的开发者社区和最成熟的前端工具链（如 npm/yarn/pnpm 包管理、Webpack/Vite 打包工具、TypeScript 类型支持）。Vue 选择 JS，可以直接复用这些工具，降低开发门槛，让更多开发者快速上手。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;对比&lt;/em&gt;：如果用 Java 写前端框架，需要额外解决包管理、构建工具、类型系统等问题，生态成本极高。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%89%E3%80%81%E5%8E%86%E5%8F%B2%E4%B8%8E%E7%A4%BE%E5%8C%BA%E5%9B%A0%E7%B4%A0%EF%BC%9Ajavascript-%E6%98%AF%E5%89%8D%E7%AB%AF%E7%9A%84%E4%BA%8B%E5%AE%9E%E6%A0%87%E5%87%86%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​三、历史与社区因素：JavaScript 是前端的事实标准​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;Vue 诞生于 2014 年，当时的前端生态已经以 JS 为主导：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​ECMAScript 标准​&lt;/strong&gt;​不断完善（ES6 引入 &lt;code&gt;class&lt;/code&gt;、&lt;code&gt;Promise&lt;/code&gt;、&lt;code&gt;let/const&lt;/code&gt; 等特性），JS 的能力大幅提升；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​Node.js​&lt;/strong&gt;​ 兴起（2009 年发布），让 JS 能在后端运行，进一步巩固了其“全栈语言”的地位；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​前端框架​&lt;/strong&gt;​（如 Angular 1.x、Backbone.js）已普遍用 JS 开发，社区习惯了 JS 的语法和思维。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;Vue 作为后来者，选择 JS 是顺应趋势，避免重复造轮子（比如重新构建一套类型系统、工具链）。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E5%9B%9B%E3%80%81%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​四、其他语言的局限性​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;虽然理论上可以用其他语言写前端框架（比如用 TypeScript 增强 JS，或用 Dart 编译成 JS），但其他语言在前端场景中存在明显短板：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8Bjava%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​Java​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;编译型语言：需要编译步骤，开发效率低（前端需要“热更新”“实时调试”）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;静态类型：虽然严谨，但前端开发中动态数据（如用户输入）的处理更灵活；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;生态脱节：Java 主要用于后端（如 Spring），前端工具链（如打包、调试）不支持 Java。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8Bpython%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​Python​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;解释型语言：虽然开发灵活，但前端需要与浏览器 API 深度交互（如操作 DOM），Python 没有原生的 DOM 操作库；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;性能问题：Python 执行效率低于 JS（浏览器用 JS 引擎优化，如 V8），复杂前端逻辑可能卡顿；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;生态不匹配：前端工具链（如 npm）不支持 Python 包，依赖管理困难。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8Btypescript%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​TypeScript​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;其实 Vue 3 已经用 TypeScript 重写了（TS 是 JS 的超集），但 TS 最终还是要编译成 JS 才能在浏览器运行。TS 的作用是​&lt;strong&gt;​增强类型检查​&lt;/strong&gt;​，而不是替代 JS——Vue 选择 JS 作为基础，TS 作为辅助，是更务实的选择。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%80%BB%E7%BB%93%EF%BC%9Avue-%E7%94%A8-js-%E7%9A%84%E6%A0%B8%E5%BF%83%E5%8E%9F%E5%9B%A0%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​总结：Vue 用 JS 的核心原因​​&lt;/strong&gt;&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​浏览器限制​&lt;/strong&gt;​：前端代码必须在浏览器中运行，而浏览器只支持 JS（及 Wasm 等补充技术）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​语言特性匹配​&lt;/strong&gt;​：JS 的动态性、函数式编程支持、对象系统，完美契合 Vue 响应式、灵活的设计目标；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​生态成熟​&lt;/strong&gt;​：JS 拥有全球最大的前端工具链和社区，Vue 复用这些资源能快速发展和普及；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​历史趋势​&lt;/strong&gt;​：JS 是前端的事实标准，Vue 顺应趋势，避免重复造轮子。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;简单说：​&lt;strong&gt;​Vue 用 JS，是因为 JS 是前端开发的“通用语言”，没有其他语言能比 JS 更适合浏览器环境，也没必要为了“尝鲜”牺牲开发效率和生态支持​&lt;/strong&gt;​。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>为什么要前后端分离</title>
        <link>https://qiuyingtyan.top/p/wei-shi-me-yao-qian-hou-duan-fen-chi/</link>
        <pubDate>Sun, 29 Jun 2025 17:26:14 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/wei-shi-me-yao-qian-hou-duan-fen-chi/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/117175864_p0_master1200-peul.webp" alt="Featured image of post 为什么要前后端分离" /&gt;&lt;p style=&#34;&#34;&gt;前后端分离是一种​&lt;strong&gt;​开发模式升级​&lt;/strong&gt;​，核心是把“前端页面渲染”和“后端数据处理”拆成两个独立的部分，各司其职。它不是“必须”，但在现代Web开发中已成为主流，主要解决了传统开发模式的痛点。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%80%E3%80%81%E4%BC%A0%E7%BB%9F%E5%BC%80%E5%8F%91%E6%A8%A1%E5%BC%8F%E7%9A%84%E7%97%9B%E7%82%B9%EF%BC%88%E5%89%8D%E5%90%8E%E7%AB%AF%E8%80%A6%E5%90%88%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​一、传统开发模式的痛点（前后端耦合）​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;在前后端分离之前，主流的开发模式是“前后端一体”（比如JSP、PHP、早期的ASP.NET）。前端（HTML/CSS/JS）和后端（Java/Python等）代码混在一个项目里，甚至写在同一个文件里（比如JSP里既有HTML又有Java代码）。这种模式有3个大问题：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87%E4%BD%8E%EF%BC%8C%E5%8D%8F%E4%BD%9C%E5%9B%B0%E9%9A%BE%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​开发效率低，协作困难​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端和后端工程师要“抢代码”：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端改个页面样式（比如调整按钮颜色），需要后端重新编译、部署整个项目；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端改个接口参数（比如把&lt;code&gt;userId&lt;/code&gt;改成&lt;code&gt;uid&lt;/code&gt;），前端所有调用这个接口的地方都要改；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;页面逻辑（比如表单验证）可能一半在前端JS写，一半在后端Java写，重复劳动多。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你做一个登录页面，前端用JS校验手机号格式，后端也要用Java再校验一遍——因为担心前端绕过校验直接发非法数据。两边代码重复，改一处漏一处。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E7%BB%B4%E6%8A%A4%E6%88%90%E6%9C%AC%E9%AB%98%EF%BC%8C%E4%BB%A3%E7%A0%81%E8%87%83%E8%82%BF%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​维护成本高，代码臃肿​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;页面逻辑和业务逻辑混在一起，代码像“浆糊”：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;一个JSP文件可能包含HTML标签、CSS样式、JavaScript脚本，还穿插着后端Java代码（比如&lt;code&gt;&amp;lt;% String name = request.getParameter(&#34;name&#34;); %&amp;gt;&lt;/code&gt;）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端为了生成动态HTML，需要拼接大量字符串（比如&lt;code&gt;out.print(&#34;&amp;lt;div&amp;gt;&#34; + data + &#34;&amp;lt;/div&amp;gt;&#34;)&lt;/code&gt;），代码可读性差，改起来容易出错。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：修一个按钮的样式，可能要翻遍整个JSP文件找对应的HTML标签和CSS类，还要注意后端有没有硬编码的样式逻辑。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E6%89%A9%E5%B1%95%E6%80%A7%E5%B7%AE%EF%BC%8C%E6%97%A0%E6%B3%95%E5%BA%94%E5%AF%B9%E5%A4%8D%E6%9D%82%E9%9C%80%E6%B1%82%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​扩展性差，无法应对复杂需求​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;传统模式适合“简单页面”，但遇到复杂交互（比如单页应用SPA、实时数据监控）就力不从心：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端无法独立优化：页面渲染依赖后端返回的完整HTML，每次数据变化都要刷新整个页面；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端压力大：除了处理业务逻辑，还要负责页面渲染、模板引擎（如Thymeleaf），浪费计算资源；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;移动端适配难：PC端页面直接套用到手机上，布局混乱，需要为不同设备写多套代码。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你想做一个实时监控大屏（像你项目中的运维监控），需要每秒更新10次数据。传统模式下，每次更新都要后端重新生成整个HTML页面，前端被动刷新，延迟高、卡顿明显。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%BA%8C%E3%80%81%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E8%A7%A3%E5%86%B3%E4%BA%86%E4%BB%80%E4%B9%88%E9%97%AE%E9%A2%98%EF%BC%9F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​二、前后端分离解决了什么问题？​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端分离后，前端和后端变成“两个独立的服务”：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​前端​&lt;/strong&gt;​：专注页面渲染、用户交互（用Vue/React/Angular等框架），通过调用后端提供的API（如&lt;code&gt;/api/server/cpu&lt;/code&gt;）获取数据；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​后端​&lt;/strong&gt;​：专注业务逻辑、数据处理（用Spring Boot/Django等框架），只负责提供API，不关心页面怎么渲染。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;这种模式带来了4大核心优势：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E5%BC%80%E5%8F%91%E6%95%88%E7%8E%87%E9%AB%98%EF%BC%8C%E5%8D%8F%E4%BD%9C%E6%9B%B4%E7%AE%80%E5%8D%95%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​开发效率高，协作更简单​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端和后端可以​&lt;strong&gt;​并行开发​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端工程师拿到后端提供的API文档（如Swagger），直接写页面调用接口，不需要等后端代码完成；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端工程师只需要保证API的正确性（返回正确的数据格式），不需要关心前端怎么渲染页面；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;代码修改互不影响：前端改样式只需调自己的CSS，后端改接口参数只需更新文档，前端同步调整即可。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你做运维监控的图表页面，前端用ECharts调用后端的&lt;code&gt;/api/metrics/cpu&lt;/code&gt;接口拿数据，后端只需要保证接口返回&lt;code&gt;{time: &#34;10:00&#34;, value: 80}&lt;/code&gt;这样的JSON，前端自己处理渲染，改颜色、调图表类型都不用后端参与。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E4%BB%A3%E7%A0%81%E6%9B%B4%E6%B8%85%E6%99%B0%EF%BC%8C%E7%BB%B4%E6%8A%A4%E6%88%90%E6%9C%AC%E4%BD%8E%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​代码更清晰，维护成本低​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端代码完全分离：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端代码（HTML/CSS/JS）只存在于前端项目（如Vue工程），后端代码（Java/Python）只存在于后端项目（如Spring Boot工程）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;页面逻辑（如按钮点击事件）和业务逻辑（如查询数据库）分开，没有重复代码；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端可以专注优化用户体验（比如页面加载速度、动画效果），后端专注优化数据处理（比如数据库查询、接口性能）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：修前端按钮的样式，只需要在前端的CSS文件里改，后端完全不用管；后端改了接口返回的数据格式（比如把&lt;code&gt;cpu&lt;/code&gt;字段改成&lt;code&gt;cpuUsage&lt;/code&gt;），只需要更新API文档，前端同步调整解析逻辑即可。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E6%89%A9%E5%B1%95%E6%80%A7%E5%BC%BA%EF%BC%8C%E8%83%BD%E5%BA%94%E5%AF%B9%E5%A4%8D%E6%9D%82%E9%9C%80%E6%B1%82%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​扩展性强，能应对复杂需求​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端分离天然支持现代Web应用的复杂需求：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​单页应用（SPA）​&lt;/strong&gt;​：前端通过AJAX/Vue Router实现页面无刷新切换（比如你项目的监控看板，切换不同服务器时不用刷新整个页面）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​多端适配​&lt;/strong&gt;​：前端可以用同一套代码适配PC、手机、平板（响应式设计），后端只需要提供通用API；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​实时交互​&lt;/strong&gt;​：通过WebSocket（你项目中的SSH终端）实现双向通信，后端主动推送数据给前端（比如服务器CPU突然飙升时，后端主动发消息给前端更新图表）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​前后端独立部署​&lt;/strong&gt;​：前端可以部署在CDN（加速访问），后端部署在云服务器（处理业务），互不影响，故障隔离。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你想给运维监控系统加一个“移动端适配”功能，前端只需要用媒体查询调整布局，后端完全不用改；如果后端需要新增一个监控指标（如内存使用率），只需要添加一个新API（&lt;code&gt;/api/metrics/memory&lt;/code&gt;），前端调用即可，无需重构页面。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E2%80%8B%E2%80%8B%E5%9B%A2%E9%98%9F%E5%8D%8F%E4%BD%9C%E6%9B%B4%E9%AB%98%E6%95%88%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;4. ​​团队协作更高效​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端可以分成两个独立的团队：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端团队专注于用户体验、交互设计（比如用Vue3+Element Plus做页面）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端团队专注于业务逻辑、数据存储（比如用Spring Boot+MyBatis-Plus写接口）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;接口文档（如Swagger）作为“合同”，明确双方的输入输出，减少沟通成本。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你项目的“子账户权限管理”功能，前端团队可以做权限控制页面（比如选择用户角色、分配服务器），后端团队做权限校验逻辑（比如用户是否有权限操作某台服务器），双方通过API文档对齐需求。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%89%E3%80%81%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%E7%9A%84%E2%80%9C%E4%BB%A3%E4%BB%B7%E2%80%9D%E4%B8%8E%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​三、前后端分离的“代价”与注意事项​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;当然，前后端分离也不是完美的，需要处理一些新问题：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E8%B7%A8%E5%9F%9F%E9%97%AE%E9%A2%98%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​跨域问题​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端和后端可能部署在不同的域名/端口（比如前端在&lt;code&gt;http://localhost:8080&lt;/code&gt;，后端在&lt;code&gt;http://localhost:8081&lt;/code&gt;），浏览器会阻止跨域请求。需要后端配置CORS（跨域资源共享）或用Nginx反向代理解决（你项目中可能用了Spring Security的CORS配置）。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%E7%BB%B4%E6%8A%A4%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​接口文档维护​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端协作依赖清晰的API文档（如参数、返回值、错误码）。需要用Swagger/OpenAPI自动生成文档，避免“接口写好了但前端不会用”的问题。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E5%89%8D%E7%AB%AF%E5%A4%8D%E6%9D%82%E5%BA%A6%E6%8F%90%E5%8D%87%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​前端复杂度提升​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端需要处理更多逻辑（比如状态管理、路由跳转、错误处理），可能需要引入框架（Vue/React）和工具（Vuex/Pinia、Vue Router），学习成本增加。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E2%80%8B%E2%80%8B%E9%A6%96%E5%B1%8F%E5%8A%A0%E8%BD%BD%E6%97%B6%E9%97%B4%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;4. ​​首屏加载时间​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端需要加载更多的JS/CSS资源，可能导致首屏加载变慢。可以通过代码分割（懒加载）、CDN加速、静态资源压缩（如图片转WebP）优化。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%80%BB%E7%BB%93%EF%BC%9A%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%89%8D%E5%90%8E%E7%AB%AF%E5%88%86%E7%A6%BB%EF%BC%9F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​总结：为什么要前后端分离？​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前后端分离的本质是​&lt;strong&gt;​“专业的人做专业的事”​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端专注于“用户看到的部分”（页面美观、交互流畅）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;后端专注于“数据处理的逻辑”（业务正确、性能高效）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;两者通过API解耦，降低协作成本，提升开发效率，更好地应对复杂Web应用的需求。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;在运维监控系统中，前后端分离尤其重要：前端需要灵活渲染各种图表（如CPU/内存使用率趋势图），后端需要高效处理大量监控数据（如InfluxDB存储、实时推送），两者独立开发能最大化发挥各自的优势。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>输入网址后页面显示的流程是什么？</title>
        <link>https://qiuyingtyan.top/p/shu-ru-wang-zhi-hou-ye-mian-xian-shi-de-liu-cheng-shi-shi-me/</link>
        <pubDate>Sun, 29 Jun 2025 17:21:22 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/shu-ru-wang-zhi-hou-ye-mian-xian-shi-de-liu-cheng-shi-shi-me/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/110762197_p0_master1200.webp" alt="Featured image of post 输入网址后页面显示的流程是什么？" /&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-%E8%BE%93%E5%85%A5%E7%BD%91%E5%9D%80-%E2%86%92-%E6%B5%8F%E8%A7%88%E5%99%A8%E8%A7%A3%E6%9E%90%E4%B8%8E%E7%BC%93%E5%AD%98%E6%A3%80%E6%9F%A5%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. 输入网址 → 浏览器解析与缓存检查​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;你在地址栏输入 &lt;code&gt;www.example.com&lt;/code&gt; 并回车后，浏览器首先做两件事：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​解析网址​&lt;/strong&gt;​：判断协议（默认 &lt;code&gt;http&lt;/code&gt; 或 &lt;code&gt;https&lt;/code&gt;）、域名（&lt;code&gt;www.example.com&lt;/code&gt;）、路径（如 &lt;code&gt;/page&lt;/code&gt;）等。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​检查缓存​&lt;/strong&gt;​：先查本地是否有该网址的缓存（包括 HTML、CSS、JS、图片等资源）。如果有且未过期（通过 &lt;code&gt;Cache-Control&lt;/code&gt; 或 &lt;code&gt;Expires&lt;/code&gt; 头判断），直接使用缓存，跳过后续网络请求（节省时间）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你昨天访问过 &lt;code&gt;www.example.com&lt;/code&gt;，今天再次输入，若缓存未过期，浏览器直接从本地读取页面显示。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B2.-dns-%E8%A7%A3%E6%9E%90%EF%BC%9A%E5%9F%9F%E5%90%8D-%E2%86%92-ip-%E5%9C%B0%E5%9D%80%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​2. DNS 解析：域名 → IP 地址​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;如果缓存中没有，浏览器需要找到 &lt;code&gt;www.example.com&lt;/code&gt; 对应的服务器 IP 地址（如 &lt;code&gt;192.168.1.1&lt;/code&gt;），这一步叫 ​&lt;strong&gt;​DNS 解析​&lt;/strong&gt;​。流程类似“查电话簿”：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​本地 DNS 缓存​&lt;/strong&gt;​：先查浏览器/操作系统的本地 DNS 缓存（可能存过该域名的 IP）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​递归查询​&lt;/strong&gt;​：若本地没有，浏览器向本地 DNS 服务器（如运营商提供的）发起请求。本地 DNS 服务器若也没有，会递归查询：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​根域名服务器​&lt;/strong&gt;​（全球 13 台，如 &lt;code&gt;a.root-servers.net&lt;/code&gt;）：告诉本地 DNS“负责 &lt;code&gt;.com&lt;/code&gt; 的顶级域名服务器（TLD）地址”。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​顶级域名服务器（TLD）​&lt;/strong&gt;​（如 &lt;code&gt;.com&lt;/code&gt; 的服务器）：告诉本地 DNS“&lt;code&gt;example.com&lt;/code&gt; 的权威 DNS 服务器地址”。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​权威 DNS 服务器​&lt;/strong&gt;​（&lt;code&gt;example.com&lt;/code&gt; 的官方服务器）：返回 &lt;code&gt;www.example.com&lt;/code&gt; 对应的 IP 地址（如 &lt;code&gt;93.184.216.34&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​缓存结果​&lt;/strong&gt;​：本地 DNS 服务器会将结果缓存，方便后续请求；浏览器也会缓存 IP，减少重复查询。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;关键&lt;/em&gt;：DNS 解析可能耗时几十到几百毫秒，所以现代浏览器会并行查询（如预解析链接中的域名）。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B3.-%E5%BB%BA%E7%AB%8B-tcp-%E8%BF%9E%E6%8E%A5%EF%BC%88%E4%B8%89%E6%AC%A1%E6%8F%A1%E6%89%8B%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​3. 建立 TCP 连接（三次握手）​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;拿到服务器 IP 后，浏览器通过 ​&lt;strong&gt;​TCP 协议​&lt;/strong&gt;​与服务器建立可靠连接。TCP 是“可靠的快递员”，需要先“确认对方在线”：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​第一次握手​&lt;/strong&gt;​：浏览器发送一个 TCP 包（&lt;code&gt;SYN=1&lt;/code&gt;），告诉服务器“我想和你建立连接”。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​第二次握手​&lt;/strong&gt;​：服务器回复（&lt;code&gt;SYN=1, ACK=1&lt;/code&gt;），表示“收到你的请求，我也想连接”。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​第三次握手​&lt;/strong&gt;​：浏览器再回复（&lt;code&gt;ACK=1&lt;/code&gt;），表示“收到你的确认，连接建立成功”。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;注意&lt;/em&gt;：如果是 HTTPS（&lt;code&gt;https://www.example.com&lt;/code&gt;），在 TCP 连接建立后，还需要进行 ​&lt;strong&gt;​TLS 握手​&lt;/strong&gt;​（协商加密算法、交换密钥），确保后续数据加密传输（防止被窃听）。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B4.-%E5%8F%91%E9%80%81-http-%E8%AF%B7%E6%B1%82%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​4. 发送 HTTP 请求​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;TCP 连接建立后，浏览器向服务器发送 ​&lt;strong&gt;​HTTP 请求​&lt;/strong&gt;​（如 &lt;code&gt;GET /page HTTP/1.1&lt;/code&gt;），请求内容包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​请求行​&lt;/strong&gt;​：方法（&lt;code&gt;GET&lt;/code&gt;/&lt;code&gt;POST&lt;/code&gt;）、路径（&lt;code&gt;/page&lt;/code&gt;）、协议版本（&lt;code&gt;HTTP/1.1&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​请求头​&lt;/strong&gt;​：浏览器信息（&lt;code&gt;User-Agent&lt;/code&gt;）、接受的响应格式（&lt;code&gt;Accept&lt;/code&gt;）、Cookies（&lt;code&gt;Cookie&lt;/code&gt;）、缓存策略（&lt;code&gt;If-None-Match&lt;/code&gt;）等。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​请求体​&lt;/strong&gt;​：如果是 &lt;code&gt;POST&lt;/code&gt; 请求，会附带表单数据或 JSON（如登录时提交的用户名密码）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：你访问 &lt;code&gt;www.example.com/login&lt;/code&gt; 并提交表单，浏览器会发送 &lt;code&gt;POST&lt;/code&gt; 请求，请求体包含 &lt;code&gt;username=admin&amp;amp;password=123&lt;/code&gt;。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B5.-%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%A4%84%E7%90%86%E8%AF%B7%E6%B1%82%E5%B9%B6%E8%BF%94%E5%9B%9E%E5%93%8D%E5%BA%94%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​5. 服务器处理请求并返回响应​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;服务器收到 HTTP 请求后，根据路径（如 &lt;code&gt;/page&lt;/code&gt;）和参数（如查询字符串 &lt;code&gt;?id=1&lt;/code&gt;），调用后端程序处理：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​静态资源​&lt;/strong&gt;​（如 HTML、CSS、图片）：直接读取服务器文件，返回给浏览器。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​动态资源​&lt;/strong&gt;​（如用户登录、数据查询）：后端代码（如 Java/Python/Node.js）执行逻辑（查数据库、调用接口），生成动态内容（如 HTML 模板填充数据）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;处理完成后，服务器返回 ​&lt;strong&gt;​HTTP 响应​&lt;/strong&gt;​，包含：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​状态码​&lt;/strong&gt;​：表示请求结果（&lt;code&gt;200 OK&lt;/code&gt; 成功，&lt;code&gt;404 Not Found&lt;/code&gt; 资源不存在，&lt;code&gt;500 Internal Error&lt;/code&gt; 服务器错误）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​响应头​&lt;/strong&gt;​：内容类型（&lt;code&gt;Content-Type: text/html&lt;/code&gt;）、缓存策略（&lt;code&gt;Cache-Control&lt;/code&gt;）、服务器信息（&lt;code&gt;Server: Nginx&lt;/code&gt;）等。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​响应体​&lt;/strong&gt;​：实际内容（如 HTML 代码、JSON 数据、图片二进制流）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：请求 &lt;code&gt;www.example.com&lt;/code&gt; 返回 &lt;code&gt;200 OK&lt;/code&gt;，响应体是 HTML 代码 &lt;code&gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Hello World&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/code&gt;。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B6.-%E6%B5%8F%E8%A7%88%E5%99%A8%E8%A7%A3%E6%9E%90%E4%B8%8E%E6%B8%B2%E6%9F%93%E9%A1%B5%E9%9D%A2%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​6. 浏览器解析与渲染页面​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;浏览器收到响应后，开始“翻译”HTML 并显示页面，核心步骤是 ​&lt;strong&gt;​构建 DOM 树 → 构建 CSSOM 树 → 合并渲染树 → 布局 → 绘制​&lt;/strong&gt;​：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%EF%BC%881%EF%BC%89%E8%A7%A3%E6%9E%90-html%EF%BC%8C%E6%9E%84%E5%BB%BA-dom-%E6%A0%91&#34;&gt;&lt;strong&gt;（1）解析 HTML，构建 DOM 树&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;浏览器从 HTML 第一行开始解析，将标签（如 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;）转换为树状结构的 ​&lt;strong&gt;​DOM 树​&lt;/strong&gt;​（Document Object Model），每个节点代表一个 HTML 元素。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;注意&lt;/em&gt;：遇到 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签时，默认会​&lt;strong&gt;​阻塞渲染​&lt;/strong&gt;​（防止 JS 修改 DOM 导致布局错乱），直到 JS 执行完毕（除非用 &lt;code&gt;async&lt;/code&gt; 或 &lt;code&gt;defer&lt;/code&gt; 标记）。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%EF%BC%882%EF%BC%89%E8%A7%A3%E6%9E%90-css%EF%BC%8C%E6%9E%84%E5%BB%BA-cssom-%E6%A0%91&#34;&gt;&lt;strong&gt;（2）解析 CSS，构建 CSSOM 树&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;同时，浏览器解析 CSS（内联/外部样式表），将样式规则（如 &lt;code&gt;color: red&lt;/code&gt;、&lt;code&gt;width: 100px&lt;/code&gt;）转换为 ​&lt;strong&gt;​CSSOM 树​&lt;/strong&gt;​（CSS Object Model），描述每个 DOM 节点的样式。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%EF%BC%883%EF%BC%89%E5%90%88%E5%B9%B6-dom-%E5%92%8C-cssom%EF%BC%8C%E7%94%9F%E6%88%90%E6%B8%B2%E6%9F%93%E6%A0%91%EF%BC%88render-tree%EF%BC%89&#34;&gt;&lt;strong&gt;（3）合并 DOM 和 CSSOM，生成渲染树（Render Tree）&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;将 DOM 树和 CSSOM 树合并，生成 ​&lt;strong&gt;​渲染树​&lt;/strong&gt;​（仅包含可见元素，如排除 &lt;code&gt;display: none&lt;/code&gt; 的节点）。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%EF%BC%884%EF%BC%89%E8%AE%A1%E7%AE%97%E5%B8%83%E5%B1%80%EF%BC%88layout%EF%BC%89&#34;&gt;&lt;strong&gt;（4）计算布局（Layout）&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;渲染树中每个节点需要确定​&lt;strong&gt;​位置和大小​&lt;/strong&gt;​（如 &lt;code&gt;div&lt;/code&gt; 在屏幕左上角，宽度 300px），这一步叫“布局”或“重排”（Reflow）。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%EF%BC%885%EF%BC%89%E7%BB%98%E5%88%B6%EF%BC%88paint%EF%BC%89&#34;&gt;&lt;strong&gt;（5）绘制（Paint）&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;根据布局结果，将每个节点的颜色、边框、阴影等视觉属性填充到屏幕像素中，这一步叫“绘制”或“重绘”（Repaint）。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：一个 &lt;code&gt;&amp;lt;div style=&#34;color:red; width:100px;&#34;&amp;gt;Hello&amp;lt;/div&amp;gt;&lt;/code&gt; 会被解析为 DOM 节点，结合 CSSOM 中的 &lt;code&gt;color:red&lt;/code&gt; 和 &lt;code&gt;width:100px&lt;/code&gt;，最终在屏幕上显示红色、宽 100px 的“Hello”文字。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B7.-%E9%A1%B5%E9%9D%A2%E6%98%BE%E7%A4%BA%E5%AE%8C%E6%88%90%EF%BC%8C%E5%90%8E%E7%BB%AD%E4%BA%A4%E4%BA%92%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​7. 页面显示完成，后续交互​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;渲染完成后，页面正式显示在屏幕上。此时浏览器还会：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​执行 JS​&lt;/strong&gt;​：如果页面中有 JS 代码（如 &lt;code&gt;script&lt;/code&gt; 标签），会触发事件（如 &lt;code&gt;onclick&lt;/code&gt;）、操作 DOM（如动态添加元素）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​监听事件​&lt;/strong&gt;​：等待用户交互（如点击链接、滚动页面），触发新的 HTTP 请求或 JS 逻辑。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;&lt;em&gt;例子&lt;/em&gt;：页面上的“提交”按钮绑定了 JS 事件，点击后会发送 &lt;code&gt;POST&lt;/code&gt; 请求到服务器，重复上述流程（DNS 解析→TCP 连接→发送请求→接收响应→重新渲染部分页面）。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%80%BB%E7%BB%93%E6%B5%81%E7%A8%8B%E5%9B%BE%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​总结流程图​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;输入网址 → 缓存检查 → DNS 解析（域名→IP） → TCP 连接（三次握手） → 发送 HTTP 请求 → 服务器处理并返回响应 → 浏览器解析渲染（DOM/CSSOM→渲染树→布局→绘制） → 显示页面 → 后续交互。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;整个过程通常需要 ​&lt;strong&gt;​几百毫秒到几秒​&lt;/strong&gt;​（取决于网络速度、服务器性能、页面复杂度），优化关键步骤（如减少 DNS 查询、压缩资源、使用 CDN）可显著提升加载速度。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>UDP和TCP的区别</title>
        <link>https://qiuyingtyan.top/p/udphe-tcpde-qu-bie/</link>
        <pubDate>Sun, 29 Jun 2025 17:18:06 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/udphe-tcpde-qu-bie/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/99407045_p0_master1200.webp" alt="Featured image of post UDP和TCP的区别" /&gt;&lt;p style=&#34;&#34;&gt;UDP 和 TCP 是传输层的两个核心协议，就像“快递员”和“邮局”的区别——一个追求速度，一个追求稳妥。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B1.-%E8%BF%9E%E6%8E%A5%E6%80%A7%EF%BC%9A%E6%98%AF%E5%90%A6%E9%9C%80%E8%A6%81%E2%80%9C%E5%85%88%E6%89%93%E7%94%B5%E8%AF%9D%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​1. 连接性：是否需要“先打电话”​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​TCP（传输控制协议）​&lt;/strong&gt;​：​&lt;strong&gt;​必须先建立连接​&lt;/strong&gt;​，像打电话一样。&lt;br&gt;发送数据前，双方要先“握手”确认对方在线（三次握手），传输结束后还要“挥手”断开连接（四次挥手）。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你要给朋友寄重要文件，得先打电话确认他在家（建立连接），送完文件再确认收货（断开连接）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​UDP（用户数据报协议）​&lt;/strong&gt;​：​&lt;strong&gt;​无需建立连接​&lt;/strong&gt;​，像发短信一样。&lt;br&gt;直接把数据打包成“包裹”（数据报）发出去，不管对方是否在线、能不能收到。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你在群里发一条“大家集合”，不用挨个确认每个人是否看到，发了就完事。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B2.-%E5%8F%AF%E9%9D%A0%E6%80%A7%EF%BC%9A%E6%98%AF%E5%90%A6%E2%80%9C%E4%BF%9D%E4%BB%B7%E8%BF%90%E8%BE%93%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​2. 可靠性：是否“保价运输”​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​TCP​&lt;/strong&gt;​：​&lt;strong&gt;​可靠传输​&lt;/strong&gt;​，像“保价快递”。&lt;br&gt;它保证数据​&lt;strong&gt;​不丢失、不重复、按顺序到达​&lt;/strong&gt;​。如果中途丢包，TCP 会自动重传；如果接收方没准备好，发送方会等待（流量控制）；如果网络拥堵，TCP 会减速（拥塞控制）。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你用微信发一段语音，微信底层用 TCP，确保你发的每一段语音对方都能完整听到，不会漏一段或乱序。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​UDP​&lt;/strong&gt;​：​&lt;strong&gt;​不可靠传输​&lt;/strong&gt;​，像“普通平信”。&lt;br&gt;发出去的数据包可能丢、可能乱序，UDP 不负责找回或排序。它只管“尽力而为”地把数据送出去，不关心结果。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你看视频直播时，偶尔卡顿或花屏，就是因为直播常用 UDP——丢几帧画面影响不大，但延迟太高会影响体验，所以直播协议会在 UDP 上加“补救”（比如前向纠错）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B3.-%E4%BC%A0%E8%BE%93%E6%96%B9%E5%BC%8F%EF%BC%9A%E6%98%AF%E2%80%9C%E6%B5%81%E6%B0%B4%E2%80%9D%E8%BF%98%E6%98%AF%E2%80%9C%E5%8C%85%E8%A3%B9%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​3. 传输方式：是“流水”还是“包裹”​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​TCP​&lt;/strong&gt;​：​&lt;strong&gt;​流式传输​&lt;/strong&gt;​，像“水管流水”。&lt;br&gt;数据没有明确的“边界”，发送方和接收方按“字节流”处理。比如你发“你好”和“世界”，接收方可能收到“你好世界”（合并了），需要自己按逻辑拆分。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​UDP​&lt;/strong&gt;​：​&lt;strong&gt;​数据报传输​&lt;/strong&gt;​，像“一个个包裹”。&lt;br&gt;每个 UDP 包（数据报）是独立的，有明确的长度和标识。接收方收到后，能直接知道这是哪个包、多长，不需要额外处理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B4.-%E5%A4%B4%E9%83%A8%E5%BC%80%E9%94%80%EF%BC%9A%E5%8C%85%E8%A3%B9%E7%9A%84%E2%80%9C%E5%8C%85%E8%A3%85%E8%B4%B9%E2%80%9D%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​4. 头部开销：包裹的“包装费”​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​TCP​&lt;/strong&gt;​：​&lt;strong&gt;​头部大​&lt;/strong&gt;​（至少 20 字节），像“精装礼盒”。&lt;br&gt;为了实现可靠传输，TCP 头部需要包含序号、确认号、窗口大小等信息，额外占用带宽。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​UDP​&lt;/strong&gt;​：​&lt;strong&gt;​头部小​&lt;/strong&gt;​（仅 8 字节），像“信封”。&lt;br&gt;只有源端口、目的端口、长度、校验和，没有复杂的控制信息，适合轻量传输。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B5.-%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF%EF%BC%9A%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E7%94%A8%E8%B0%81%EF%BC%9F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​5. 适用场景：什么时候用谁？​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​TCP 适合​&lt;/strong&gt;​：需要​&lt;strong&gt;​可靠、有序​&lt;/strong&gt;​的场景，比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;网页浏览（HTTP 基于 TCP）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;文件下载（FTP 基于 TCP）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;邮件发送（SMTP 基于 TCP）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;你的运维监控系统中，客户端上报数据（用 HTTP 即 TCP），因为需要确保数据完整到达服务端。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​UDP 适合​&lt;/strong&gt;​：需要​&lt;strong&gt;​实时性、低延迟​&lt;/strong&gt;​，允许少量丢包的场景，比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;视频通话（丢几帧画面影响小，但延迟高会卡）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;在线游戏（移动指令延迟高会“操作跟手”）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;DNS 查询（域名解析请求小，丢包可重试）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;物联网传感器（比如温度上报，偶尔丢一个数据不影响整体趋势）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%80%BB%E7%BB%93%E5%AF%B9%E6%AF%94%E8%A1%A8%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​总结对比表​​&lt;/strong&gt;&lt;/h3&gt;&lt;div style=&#34;overflow-x: auto; overflow-y: hidden;&#34;&gt;&lt;table style=&#34;width: 300px&#34;&gt;&lt;colgroup&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;TCP&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;UDP&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;连接性&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;必须建立连接（三次握手）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;无需连接&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;可靠性&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;可靠（不丢包、不乱序）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;不可靠（可能丢包、乱序）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;传输方式&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;流式（无边界）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;数据报（有边界）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;头部开销&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;至少 20 字节&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;仅 8 字节&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;典型场景&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;网页、文件下载、邮件&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;视频通话、游戏、DNS&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: none; border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;你的项目场景&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: none; border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;客户端上报数据（HTTP/TCP）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: none; border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;若需实时监控（如高频指标）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​回到运维监控系统​&lt;/strong&gt;​：&lt;br&gt;客户端上报数据用 HTTP（基于 TCP），因为需要确保每一条监控数据（比如 CPU 使用率）完整到达服务端，不能丢。而如果你们需要实时展示某些高频指标（比如每秒 100 次的心跳），可能会用 UDP——但需要在应用层自己处理丢包（比如丢包后用前一个值填充），因为 UDP 不保证可靠。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;简单说：​&lt;strong&gt;​需要稳妥选 TCP，需要速度选 UDP​&lt;/strong&gt;​。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Http和WebSocket通信的区别</title>
        <link>https://qiuyingtyan.top/p/httphe-websockettong-xin-de-qu-bie/</link>
        <pubDate>Sun, 29 Jun 2025 17:15:37 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/httphe-websockettong-xin-de-qu-bie/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/816f5072-3ca1-47a4-9f3b-789ebde14a8d.webp" alt="Featured image of post Http和WebSocket通信的区别" /&gt;&lt;p style=&#34;&#34;&gt;HTTP 和 WebSocket 是两种不同的网络通信协议，核心区别在于​&lt;strong&gt;​通信方向​&lt;/strong&gt;​、​&lt;strong&gt;​连接状态​&lt;/strong&gt;​和​&lt;strong&gt;​适用场景​&lt;/strong&gt;​。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B1.-%E9%80%9A%E4%BF%A1%E6%96%B9%E5%90%91%EF%BC%9A%E5%8D%95%E5%90%91-vs-%E5%85%A8%E5%8F%8C%E5%B7%A5%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​1. 通信方向：单向 vs 全双工​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​HTTP​&lt;/strong&gt;​：​&lt;strong&gt;​单向请求-响应模式​&lt;/strong&gt;​。&lt;br&gt;只能由客户端主动发起请求（比如打开网页、点按钮查数据），服务器收到请求后返回响应，之后连接就关闭了（HTTP/1.1 虽然支持长连接，但还是“你问我答”的模式）。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你去奶茶店点单（客户端请求），店员做奶茶后给你（服务器响应），之后店员等你下次再来（连接关闭）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​WebSocket​&lt;/strong&gt;​：​&lt;strong&gt;​全双工双向通信​&lt;/strong&gt;​。&lt;br&gt;连接建立后，客户端和服务器可以​&lt;strong&gt;​随时互相发消息​&lt;/strong&gt;​，不需要一方先发起请求。就像两个人开着视频通话，你说一句，我说一句，不用每次都“喂，听得到吗？”。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你和朋友开微信语音，你能随时说话，朋友也能随时插话，不用等对方先开口。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B2.-%E8%BF%9E%E6%8E%A5%E7%8A%B6%E6%80%81%EF%BC%9A%E6%97%A0%E7%8A%B6%E6%80%81-vs-%E9%95%BF%E8%BF%9E%E6%8E%A5%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​2. 连接状态：无状态 vs 长连接​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​HTTP​&lt;/strong&gt;​：​&lt;strong&gt;​无状态​&lt;/strong&gt;​。&lt;br&gt;每次请求都是独立的，服务器不记得“你是谁”（除非用 Cookie/Token 手动记录）。比如你登录后刷新页面，服务器需要重新验证你的身份。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你去超市买东西，每次结账都要出示会员卡（Token），店员不会记住你之前买过什么。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​WebSocket​&lt;/strong&gt;​：​&lt;strong&gt;​长连接​&lt;/strong&gt;​。&lt;br&gt;一旦连接建立（握手阶段），双方保持“在线”状态，直到一方主动关闭。服务器能记住客户端的身份（比如通过 Token 鉴权），适合需要持续交互的场景。&lt;br&gt;&lt;em&gt;例子&lt;/em&gt;：你在家开空调，用手机 APP 远程控制，APP 和空调服务器保持长连接，你能随时查看温度、调整模式，不用每次操作都重新连接。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B3.-%E5%8D%8F%E8%AE%AE%E5%B1%82%E7%BA%A7%E4%B8%8E%E6%8F%A1%E6%89%8B%E6%96%B9%E5%BC%8F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​3. 协议层级与握手方式​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​HTTP​&lt;/strong&gt;​：基于 TCP 的应用层协议，直接使用 TCP 连接。&lt;br&gt;每次请求都要携带完整的 HTTP 头部（比如 &lt;code&gt;Host&lt;/code&gt;、&lt;code&gt;Cookie&lt;/code&gt;、&lt;code&gt;User-Agent&lt;/code&gt;），冗余信息多，适合“一次性”数据传输。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​WebSocket​&lt;/strong&gt;​：基于 TCP 的应用层协议，但​&lt;strong&gt;​通过 HTTP 握手升级​&lt;/strong&gt;​。&lt;br&gt;连接建立时，客户端先发一个 HTTP 请求（&lt;code&gt;Upgrade: websocket&lt;/code&gt;），服务器同意后，双方切换为 WebSocket 协议，之后的通信用更小的帧头（仅 2-10 字节），效率更高。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B4.-%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​4. 适用场景​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​HTTP 适合​&lt;/strong&gt;​：&lt;br&gt;传统的“客户端发起请求，服务器返回结果”的场景，比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;刷网页（加载 HTML/CSS/JS）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;调用 API 查数据（比如查天气、查订单）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;提交表单（登录、下单）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​WebSocket 适合​&lt;/strong&gt;​：&lt;br&gt;需要​&lt;strong&gt;​实时双向交互​&lt;/strong&gt;​的场景，比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;聊天软件（消息实时推送）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;监控看板（服务器状态实时更新）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;远程控制（比如你项目中用 WebSocket 实现的 SSH 终端，打字、回显实时同步）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;股票行情（股价变动秒级推送）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%80%BB%E7%BB%93%E5%AF%B9%E6%AF%94%E8%A1%A8%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​总结对比表​​&lt;/strong&gt;&lt;/h3&gt;&lt;div style=&#34;overflow-x: auto; overflow-y: hidden;&#34;&gt;&lt;table style=&#34;width: 300px&#34;&gt;&lt;colgroup&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;特性&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;HTTP&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;WebSocket&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;通信方向&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;单向（客户端→服务器）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;全双工（双向）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;连接状态&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;无状态（每次请求独立）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;长连接（保持在线）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;协议层级&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;纯应用层（基于 TCP）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;应用层（HTTP 握手后升级）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;头部开销&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-width: 0.8px; border-style: solid; border-color: rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;大（每次请求带完整头部）&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;小（仅初始握手，后续帧头很小）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: none; border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;典型场景&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: none; border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;网页加载、API 调用、表单提交&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: none; border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;实时聊天、监控、远程控制&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;hr&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;在运维监控系统里用 WebSocket 实现 SSH 远程控制，就是典型的“需要实时双向交互”的场景——用户在网页敲命令，服务器实时返回执行结果，这用 HTTP 的“请求-响应”模式根本做不到（每次发命令都要等服务器响应，无法实时显示输入的字符）。所以选 WebSocket 是因为它的全双工特性，能保证操作和反馈的实时性。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>rbac是怎么写的？</title>
        <link>https://qiuyingtyan.top/p/rbacshi-zen-me-xie-de/</link>
        <pubDate>Sun, 29 Jun 2025 17:07:17 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/rbacshi-zen-me-xie-de/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/86499845_p0_master1200.webp" alt="Featured image of post rbac是怎么写的？" /&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%80%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93%E8%AE%BE%E8%AE%A1%EF%BC%9A%E7%90%86%E6%B8%85%E8%A7%92%E8%89%B2-%E6%9D%83%E9%99%90-%E7%94%A8%E6%88%B7%E7%9A%84%E5%85%B3%E7%B3%BB%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​一、数据库设计：理清角色-权限-用户的关系​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;RBAC 的核心是三张核心表 + 两张关联表，具体如下（简化版）：&lt;/p&gt;&lt;div style=&#34;overflow-x: auto; overflow-y: hidden;&#34;&gt;&lt;table style=&#34;width: 200px&#34;&gt;&lt;colgroup&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;col style=&#34;width: 100px&#34;&gt;&lt;/colgroup&gt;&lt;tbody&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;表名&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;th colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: none; border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: bold 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(237, 237, 237); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_user&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;用户表（存储账号、密码、状态等）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_role&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;角色表（比如「系统管理员」「普通运维」「只读用户」）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_permission&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;权限表（具体操作权限，比如「server:manage」「monitor:view」）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_user_role&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;用户-角色关联表（一个用户可有多个角色）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_role_perm&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;角色-权限关联表（一个角色可拥有多个权限）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: 0.8px solid rgb(224, 224, 224); border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_server&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: 0.8px solid rgb(224, 224, 224); border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;服务器表（存储被管理的服务器信息，比如IP、名称）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&#34;margin: 0px; padding: 0px; border: 0px; font: inherit; vertical-align: baseline; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important;&#34;&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: 0.8px solid rgb(224, 224, 224); border-bottom: none; border-left: none; border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;sys_server_role&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;&lt;td colspan=&#34;1&#34; rowspan=&#34;1&#34; colwidth=&#34;100&#34; style=&#34;margin: 0px; padding: 10px 12px; border-top: 0.8px solid rgb(224, 224, 224); border-right: none; border-bottom: none; border-left: 0.8px solid rgb(224, 224, 224); border-image: none 100% / 1 / 0 stretch; font: 400 14px / 1.6 &amp;quot;PingFang SC&amp;quot;, -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft YaHei UI&amp;quot;, &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;Source Han Sans CN&amp;quot;, sans-serif; vertical-align: middle; scrollbar-color: rgb(0, 0, 0) rgb(153, 153, 153) !important; background-color: rgb(255, 255, 255); color: rgba(0, 0, 0, 0.9); text-align: center; max-width: 448px; white-space: normal; box-sizing: border-box;&#34;&gt;&lt;p style=&#34;&#34;&gt;服务器-角色关联表（一个服务器可分配给多个角色，实现「某服务器由某角色管理」）&lt;/p&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;举个例子：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;用户A的角色是「运维组」，「运维组」角色拥有「server:manage」权限；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务器1被分配了「运维组」角色，所以用户A能管理服务器1；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务器2被分配了「管理员」角色，用户A没有「管理员」角色，所以管不了服务器2。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%BA%8C%E3%80%81%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%AE%9E%E7%8E%B0%EF%BC%9Aspringsecurity-%E6%95%B4%E5%90%88-jwt-%2B-rbac%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​二、服务端实现：SpringSecurity 整合 JWT + RBAC​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;我们用 SpringSecurity 做权限校验，结合 JWT 实现无状态认证，核心步骤如下：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E7%94%A8%E6%88%B7%E8%AE%A4%E8%AF%81%EF%BC%88userdetailsservice%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​自定义用户认证（UserDetailsService）​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;用户登录时，前端传账号密码，服务端通过 &lt;code&gt;UserDetailsService&lt;/code&gt; 加载用户信息（包括角色、权限）。这里需要从数据库查用户，再查关联的角色和权限，封装成 &lt;code&gt;UserDetails&lt;/code&gt; 对象返回。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;@Service
public class CustomUserDetailsService implements UserDetailsService {
&lt;pre&gt;&lt;code&gt;@Autowired
private SysUserMapper userMapper; // MyBatis-Plus 用户表Mapper

@Override
public UserDetails loadUserByUsername(String username) {
    // 1. 查用户是否存在
    SysUser user = userMapper.selectOne(Wrappers.lambdaQuery(SysUser.class).eq(SysUser::getUsername, username));
    if (user == null) {
        throw new UsernameNotFoundException(&amp;quot;用户不存在&amp;quot;);
    }

    // 2. 查用户的所有角色（通过 sys_user_role 关联表）
    List&amp;amp;lt;SysRole&amp;amp;gt; roles = roleMapper.selectRolesByUserId(user.getId());

    // 3. 查角色对应的所有权限（通过 sys_role_perm 关联表）
    List&amp;amp;lt;String&amp;amp;gt; perms = roles.stream()
            .flatMap(role -&amp;amp;gt; permMapper.selectPermsByRoleId(role.getId()).stream())
            .collect(Collectors.toList());

    // 4. 封装成 SpringSecurity 的 UserDetails（包含权限）
    return new CustomUserDetails(
        user.getUsername(), 
        user.getPassword(), 
        user.getStatus() == 1, // 是否启用
        true, true, true, 
        Collections.emptyList(), // 权限集合（这里用字符串列表，实际可用 Permission 对象）
        roles, 
        perms
    );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E6%9D%83%E9%99%90%E6%8B%A6%E6%88%AA%E4%B8%8E%E6%A0%A1%E9%AA%8C%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​权限拦截与校验​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;通过 &lt;code&gt;@PreAuthorize&lt;/code&gt; 注解或自定义拦截器，校验用户是否有权限访问某个接口或操作。比如：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;@RestController
@RequestMapping(&amp;quot;/server&amp;quot;)
public class ServerController {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// 只有拥有 &#39;server:manage&#39; 权限的用户才能访问
@PreAuthorize(&amp;quot;hasAuthority(&#39;server:manage&#39;)&amp;quot;)
@PostMapping(&amp;quot;/add&amp;quot;)
public Result addServer(@RequestBody Server server) {
    // 添加服务器逻辑
}

// 拥有 &#39;server:view&#39; 权限的用户都能查看
@PreAuthorize(&amp;quot;hasAuthority(&#39;server:view&#39;)&amp;quot;)
@GetMapping(&amp;quot;/list&amp;quot;)
public Result listServers() {
    // 查询服务器列表
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E5%8A%A8%E6%80%81%E6%9D%83%E9%99%90%E5%8A%A0%E8%BD%BD%EF%BC%88%E8%A7%A3%E5%86%B3%E8%A7%92%E8%89%B2%2F%E6%9D%83%E9%99%90%E5%8F%98%E6%9B%B4%E5%90%8E%E7%BC%93%E5%AD%98%E9%97%AE%E9%A2%98%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​动态权限加载（解决角色/权限变更后缓存问题）​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;因为用了 JWT（无状态），用户权限变更后，旧 JWT 仍然有效，可能导致权限未及时更新。我们的解决方法是：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;在 &lt;code&gt;sys_user&lt;/code&gt; 表加 &lt;code&gt;version&lt;/code&gt; 字段（每次修改用户权限时 &lt;code&gt;version+1&lt;/code&gt;）；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;JWT 中携带 &lt;code&gt;version&lt;/code&gt; 信息；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;每次请求时，服务端校验 JWT 中的 &lt;code&gt;version&lt;/code&gt; 是否与数据库一致，不一致则拒绝请求并让用户重新登录。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;// 自定义 JWT 校验过滤器（关键逻辑）
public class JwtAuthenticationFilter extends OncePerRequestFilter {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
    String token = extractToken(request);
    if (token != null) {
        try {
            // 解析 JWT 得到用户信息和 version
            Claims claims = jwtUtil.parseToken(token);
            String username = claims.getSubject();
            Integer jwtVersion = claims.get(&amp;quot;version&amp;quot;, Integer.class);

            // 查数据库用户的当前 version
            SysUser user = userMapper.selectByUsername(username);
            if (user.getVersion() == null || !user.getVersion().equals(jwtVersion)) {
                // 版本不一致，权限可能变更，拒绝请求
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                return;
            }

            // 校验通过，生成 UserDetails 并设置到 SecurityContext
            UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
            );
            SecurityContextHolder.getContext().setAuthentication(auth);
            filterChain.doFilter(request, response);
        } catch (JwtException e) {
            // Token 无效，返回未授权
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
        }
    } else {
        filterChain.doFilter(request, response);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E2%80%8B%E2%80%8B%E6%9C%8D%E5%8A%A1%E5%99%A8-%E8%A7%92%E8%89%B2%E5%85%B3%E8%81%94%E7%9A%84%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;4. ​​服务器-角色关联的权限控制​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;除了用户角色的权限，还要控制「用户是否能管理某台具体服务器」。比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;用户A有「运维组」角色，该角色被分配了服务器1和服务器2；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;用户A访问服务器3的管理接口时，需要校验「运维组」是否拥有服务器3的管理权限。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;这部分在服务端接口中额外处理：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;@PostMapping(&amp;quot;/operate/{serverId}&amp;quot;)
public Result operateServer(@PathVariable Long serverId, @RequestBody OperateReq req) {
// 1. 当前用户
String username = SecurityContextHolder.getContext().getAuthentication().getName();
// 2. 查用户拥有的角色
List&amp;lt;SysRole&amp;gt; userRoles = roleService.getUserRoles(username);
// 3. 查这些角色是否被分配了当前服务器
boolean hasPermission = serverRoleService.checkServerAssignedToRoles(serverId, userRoles);
if (!hasPermission) {
throw new AccessDeniedException(&amp;ldquo;无权限操作该服务器&amp;rdquo;);
}
// 4. 执行操作&amp;hellip;
}&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%89%E3%80%81%E5%89%8D%E7%AB%AF%E9%85%8D%E5%90%88%EF%BC%9A%E5%8A%A8%E6%80%81%E8%8F%9C%E5%8D%95%E4%B8%8E%E6%8C%89%E9%92%AE%E6%9D%83%E9%99%90%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​三、前端配合：动态菜单与按钮权限​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端（Vue3）需要根据用户权限动态渲染菜单和按钮，避免显示无权限的功能。具体步骤：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E7%99%BB%E5%BD%95%E5%90%8E%E8%8E%B7%E5%8F%96%E6%9D%83%E9%99%90%E4%BF%A1%E6%81%AF%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​登录后获取权限信息​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;用户登录成功后，后端返回用户的角色、权限列表（比如 &lt;code&gt;[&amp;lsquo;server:manage&amp;rsquo;, &amp;lsquo;monitor:view&amp;rsquo;]&lt;/code&gt;），前端存储到 Vuex 或 Pinia 中。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E5%8A%A8%E6%80%81%E7%94%9F%E6%88%90%E8%8F%9C%E5%8D%95%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​动态生成菜单​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;菜单数据从后端获取（根据用户权限过滤），比如：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;管理员看到「服务器管理」「监控看板」「用户管理」；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;普通运维只看到「服务器管理」「监控看板」。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;pre&gt;&lt;code&gt;// Vue 组件中获取菜单
async function getMenus() {
const res = await axios.get(&amp;rsquo;/api/menus&amp;rsquo;, {
headers: { Authorization: &lt;code&gt;Bearer ${token}&lt;/code&gt; }
});
// 根据用户权限过滤菜单（后端已处理，前端直接渲染）
store.commit(&amp;lsquo;setMenus&amp;rsquo;, res.data);
}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E6%8C%89%E9%92%AE%E7%BA%A7%E6%9D%83%E9%99%90%E6%8E%A7%E5%88%B6%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​按钮级权限控制​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;通过自定义指令 &lt;code&gt;v-permission&lt;/code&gt; 控制按钮是否显示：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;// 注册全局指令
app.directive(&amp;lsquo;permission&amp;rsquo;, {
mounted(el, binding) {
const perms = store.state.user.permissions; // 用户权限列表
const requiredPerm = binding.value; // 需要的权限（如 &amp;lsquo;server:manage&amp;rsquo;）
if (!perms.includes(requiredPerm)) {
el.parentNode?.removeChild(el); // 无权限则移除按钮
}
}
});&lt;/p&gt;
&lt;p&gt;// 使用示例
&amp;lt;button v-permission=&amp;quot;&amp;lsquo;server:manage&amp;rsquo;&amp;quot;&amp;gt;删除服务器&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E5%9B%9B%E3%80%81%E5%85%B3%E9%94%AE%E7%BB%86%E8%8A%82%E4%B8%8E%E8%B8%A9%E5%9D%91%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​四、关键细节与踩坑​​&lt;/strong&gt;&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​权限缓存​&lt;/strong&gt;​：用户权限信息存在 Redis 中（键：&lt;code&gt;user:perm:${username}&lt;/code&gt;），避免每次请求都查数据库。用户登出或权限变更时，删除对应缓存。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​JWT 与 RBAC 结合​&lt;/strong&gt;​：JWT 中除了用户信息，还要存角色/权限的摘要（比如角色ID列表），避免每次请求都查数据库（但最终校验还是以数据库为准）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​动态路由​&lt;/strong&gt;​：前端路由需要根据权限动态添加（比如用 &lt;code&gt;router.addRoute()&lt;/code&gt;），避免无权限的路由被访问。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​服务器-角色关联的灵活性​&lt;/strong&gt;​：通过 &lt;code&gt;sys_server_role&lt;/code&gt; 表实现「多对多」关系，一个服务器可分配给多个角色，一个角色可管理多个服务器，满足复杂权限需求。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;总结来说， RBAC 实现围绕「用户-角色-权限-服务器」四者关系，通过 SpringSecurity 做权限校验，JWT 做无状态认证，前端动态渲染，最终实现了「不同账户管理不同服务器」的灵活权限控制。&lt;/p&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>websocket怎么写的？</title>
        <link>https://qiuyingtyan.top/p/websocketzen-me-xie-de/</link>
        <pubDate>Sun, 29 Jun 2025 17:04:52 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/websocketzen-me-xie-de/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/116506885_p0_master1200.webp" alt="Featured image of post websocket怎么写的？" /&gt;&lt;p style=&#34;&#34;&gt;其实项目里用WebSocket主要是为了前端能通过网页直接操作后端的服务器，比如执行命令、看实时输出，就像本地连SSH一样。那我分服务端和前端两部分说说吧。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%9F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​服务端怎么实现的？​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;首先，服务端得支持WebSocket协议。Spring Boot有内置的WebSocket支持，我们用了&lt;code&gt;@EnableWebSocketMessageBroker&lt;/code&gt;来配置。核心是配两个东西：​&lt;strong&gt;​端点​&lt;/strong&gt;​和​&lt;strong&gt;​消息代理​&lt;/strong&gt;​。端点就是前端连过来的入口，比如&lt;code&gt;/ssh-websocket&lt;/code&gt;，前端通过这个地址建立连接。消息代理的话，我们用&lt;code&gt;SimpleBroker&lt;/code&gt;来处理订阅，前端发送的消息会通过&lt;code&gt;/app&lt;/code&gt;前缀的路径到服务端，服务端处理完再通过&lt;code&gt;/topic&lt;/code&gt;推送给前端。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;然后，​&lt;strong&gt;​鉴权​&lt;/strong&gt;​是关键。因为不是谁都能连这个WebSocket，得确保是登录过的用户。我们在握手阶段（也就是前端刚连上的时候）做了校验：前端请求头里带着JWT Token，服务端从请求里掏出来，用自定义的&lt;code&gt;JwtTokenProvider&lt;/code&gt;验证是否有效。如果无效，直接拒绝连接；有效的话，就把用户信息（比如用户名）存到&lt;code&gt;attributes&lt;/code&gt;里，后面处理消息时能取到。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;接下来是​&lt;strong&gt;​会话管理​&lt;/strong&gt;​。每个连进来的WebSocket会话（&lt;code&gt;WebSocketSession&lt;/code&gt;）得和具体的SSH会话绑定。我们用了JSCH库来连服务器，每个用户连服务器前，得先创建一个JSCH的&lt;code&gt;Session&lt;/code&gt;（比如输入用户名、密码、服务器地址）。为了不让这些会话乱，我们用了一个&lt;code&gt;ConcurrentHashMap&lt;/code&gt;来存——键是WebSocket的&lt;code&gt;sessionId&lt;/code&gt;，值是对应的JSCH &lt;code&gt;Session&lt;/code&gt;。这样前端发命令时，服务端能根据&lt;code&gt;sessionId&lt;/code&gt;找到对应的SSH连接，执行命令并返回结果。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;处理消息的时候，前端发来的消息是JSON格式的，比如&lt;code&gt;{&#34;type&#34;:&#34;command&#34;, &#34;content&#34;:&#34;ls -l&#34;}&lt;/code&gt;。服务端解析后，如果是执行命令，就用JSCH的&lt;code&gt;ChannelExec&lt;/code&gt;执行，把结果读出来再封装成JSON（比如&lt;code&gt;{&#34;type&#34;:&#34;output&#34;, &#34;content&#34;:&#34;xxx&#34;}&lt;/code&gt;），通过WebSocket发回前端。如果是调整窗口大小（比如用户拖拽终端窗口），就调用JSCH的&lt;code&gt;setPtySize&lt;/code&gt;方法改终端尺寸。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;还有，前端断开的时候，服务端得清理资源。我们在&lt;code&gt;afterConnectionClosed&lt;/code&gt;方法里，根据&lt;code&gt;sessionId&lt;/code&gt;把对应的JSCH &lt;code&gt;Session&lt;/code&gt;关掉，避免资源泄露。&lt;/p&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E5%89%8D%E7%AB%AF%E6%80%8E%E4%B9%88%E5%AE%9E%E7%8E%B0%E7%9A%84%EF%BC%9F%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​前端怎么实现的？​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端用的是Vue3，主要依赖&lt;code&gt;SockJS&lt;/code&gt;和&lt;code&gt;StompJS&lt;/code&gt;——因为不是所有浏览器都支持原生的WebSocket，&lt;code&gt;SockJS&lt;/code&gt;能兼容，&lt;code&gt;StompJS&lt;/code&gt;用来处理消息协议。然后，用&lt;code&gt;Xterm.js&lt;/code&gt;来渲染终端界面，它模拟了真实的命令行效果，支持输入、输出、光标移动这些。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;具体步骤大概是这样的：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​建立连接​&lt;/strong&gt;​：页面加载时，前端用&lt;code&gt;SockJS&lt;/code&gt;连服务端的&lt;code&gt;/ssh-websocket&lt;/code&gt;端点，再用&lt;code&gt;Stomp&lt;/code&gt;订阅消息。比如：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;const socket = new SockJS(&#39;/api/ssh-websocket&#39;); // 实际路径可能带前缀
this.stompClient = Stomp.over(socket);
this.stompClient.connect({}, () =&amp;gt; {
  // 连成功后订阅消息，比如服务端返回的输出会到这里
  this.stompClient.subscribe(&#39;/user/topic/ssh-output&#39;, message =&amp;gt; {
    const res = JSON.parse(message.body);
    if (res.type === &#39;OUTPUT&#39;) {
      this.terminal.write(res.content); // 输出到终端
    }
  });
});&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​初始化终端​&lt;/strong&gt;​：用&lt;code&gt;Xterm.js&lt;/code&gt;创建一个终端实例，挂载到页面的某个div上，设置主题（比如暗黑模式）、字体大小这些。然后监听用户的键盘输入，用户按键盘时，调用&lt;code&gt;terminal.onData(data)&lt;/code&gt;拿到输入的内容，通过WebSocket发给服务端。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​发送命令和调整窗口​&lt;/strong&gt;​：用户输入命令后，前端把命令包装成JSON（比如&lt;code&gt;{&#34;type&#34;:&#34;command&#34;, &#34;content&#34;:&#34;ls&#34;}&lt;/code&gt;），通过&lt;code&gt;stompClient.send(&#39;/app/ssh-command&#39;, {}, JSON.stringify(payload))&lt;/code&gt;发给服务端。如果是调整窗口大小（比如浏览器窗口变了），就获取终端的行数和列数，同样发消息给服务端，让后端调整JSCH会话的终端尺寸。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​处理断开和重连​&lt;/strong&gt;​：如果WebSocket断了，前端会自动尝试重连（可能需要加个延迟，避免一直连不上）。比如在&lt;code&gt;disconnect&lt;/code&gt;事件里，设置个定时器，过几秒再试一次。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;hr&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91%E5%92%8C%E8%A7%A3%E5%86%B3%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​遇到的坑和解决​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;其实刚开始踩了不少坑。比如，​&lt;strong&gt;​会话绑定​&lt;/strong&gt;​的时候，如果用户开了多个标签页，每个标签页的&lt;code&gt;sessionId&lt;/code&gt;不一样，得确保每个标签页的SSH会话独立，不然会串命令。后来用&lt;code&gt;ConcurrentHashMap&lt;/code&gt;存&lt;code&gt;sessionId&lt;/code&gt;和JSCH会话的映射，每个标签页独立管理，解决了这个问题。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;还有​&lt;strong&gt;​鉴权失败​&lt;/strong&gt;​的情况，前端连WebSocket时没带Token或者Token过期，服务端直接拒绝，但前端没提示。后来在连接失败的回调里加了个提示，让用户重新登录。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;另外，​&lt;strong&gt;​命令输出的实时性​&lt;/strong&gt;​也有问题。刚开始服务端执行命令后，一次性把所有输出发给前端，如果命令输出很大（比如&lt;code&gt;ls -l&lt;/code&gt;很多文件），前端渲染会卡。后来改成按行流式发送，服务端读一行发一行，前端逐行渲染，体验好多了。&lt;/p&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;总的来说，WebSocket的核心是服务端和前端配合好消息格式、会话管理和鉴权，确保命令能准确执行，结果能实时显示。虽然中间遇到了一些细节问题，但通过调试和优化都解决了。&lt;/p&gt;
</description>
        </item>
        <item>
        <title>MySQL中连表的问题是怎么解决的？左连接内连接之类的区别是什么？</title>
        <link>https://qiuyingtyan.top/p/mysql-lianbiao-lianjie/</link>
        <pubDate>Sun, 29 Jun 2025 17:00:46 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/mysql-lianbiao-lianjie/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/101796526_p0_master1200.webp" alt="Featured image of post MySQL中连表的问题是怎么解决的？左连接内连接之类的区别是什么？" /&gt;&lt;p style=&#34;&#34;&gt;在 MySQL 中，连表（多表连接查询）是处理多表关联数据的核心操作，主要用于从多个表中提取关联数据。以下从​&lt;strong&gt;​连表问题的解决思路​&lt;/strong&gt;​、​&lt;strong&gt;​常见连接类型的区别（重点左连接 vs 内连接）​&lt;/strong&gt;​两个方面详细说明：&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%B8%80%E3%80%81mysql-%E8%BF%9E%E8%A1%A8%E9%97%AE%E9%A2%98%E7%9A%84%E8%A7%A3%E5%86%B3%E6%80%9D%E8%B7%AF&#34;&gt;&lt;strong&gt;一、MySQL 连表问题的解决思路&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;连表问题的本质是通过​&lt;strong&gt;​关联字段​&lt;/strong&gt;​将多个表的数据按逻辑关系合并，核心步骤如下：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E6%98%8E%E7%A1%AE%E4%B8%9A%E5%8A%A1%E9%9C%80%E6%B1%82&#34;&gt;&lt;strong&gt;1. 明确业务需求&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;首先需要明确：需要哪些表的数据？表之间的关联关系（如用户表 → 订单表，通过 &lt;code&gt;user_id&lt;/code&gt; 关联）？需要过滤什么条件？最终要展示哪些字段？&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E9%80%89%E6%8B%A9%E5%90%88%E9%80%82%E7%9A%84%E8%BF%9E%E6%8E%A5%E7%B1%BB%E5%9E%8B&#34;&gt;&lt;strong&gt;2. 选择合适的连接类型&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;根据业务需求选择连接类型（内连接、左连接、右连接等），这是解决连表问题的关键。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E7%BC%96%E5%86%99%E8%BF%9E%E6%8E%A5%E8%AF%AD%E6%B3%95&#34;&gt;&lt;strong&gt;3. 编写连接语法&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;使用 &lt;code&gt;JOIN&lt;/code&gt; 关键字（或隐式连接的逗号分隔表名 + &lt;code&gt;WHERE&lt;/code&gt; 条件）定义连接关系，核心是：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;ON&lt;/code&gt; 子句：定义表间的关联条件（如 &lt;code&gt;user.id = order.user_id&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;WHERE&lt;/code&gt; 子句：对连接后的结果集进一步过滤（可选）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E5%A4%84%E7%90%86-null-%E5%80%BC%E5%92%8C%E9%87%8D%E5%A4%8D%E6%95%B0%E6%8D%AE&#34;&gt;&lt;strong&gt;4. 处理 NULL 值和重复数据&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;连接可能导致某些字段为 &lt;code&gt;NULL&lt;/code&gt;（如左连接中右表无匹配的行），或因关联条件不严谨导致重复数据（如一对多关系未正确过滤），需通过 &lt;code&gt;COALESCE()&lt;/code&gt;、&lt;code&gt;DISTINCT&lt;/code&gt; 或业务逻辑处理。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BA%8C%E3%80%81%E5%B7%A6%E8%BF%9E%E6%8E%A5%EF%BC%88left-join%EF%BC%89%E4%B8%8E%E5%86%85%E8%BF%9E%E6%8E%A5%EF%BC%88inner-join%EF%BC%89%E7%9A%84%E5%8C%BA%E5%88%AB&#34;&gt;&lt;strong&gt;二、左连接（LEFT JOIN）与内连接（INNER JOIN）的区别&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;MySQL 支持多种连接类型，最常用的是 ​&lt;strong&gt;​内连接（INNER JOIN）​&lt;/strong&gt;​ 和 ​&lt;strong&gt;​左连接（LEFT JOIN）​&lt;/strong&gt;​，核心区别在于​&lt;strong&gt;​是否保留主表的所有行​&lt;/strong&gt;​。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E5%86%85%E8%BF%9E%E6%8E%A5%EF%BC%88inner-join%EF%BC%89&#34;&gt;&lt;strong&gt;1. 内连接（INNER JOIN）&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​逻辑​&lt;/strong&gt;​：仅返回两个表中​&lt;strong&gt;​关联字段完全匹配​&lt;/strong&gt;​的行（即同时存在于主表和关联表中的数据）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​特点​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;若主表某行在关联表中无匹配，则该行不会出现在结果中。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;是最严格的连接类型，适合“需要关联表中存在对应数据”的场景（如查询“有订单的用户”）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​示例​&lt;/strong&gt;​：&lt;br&gt;用户表（&lt;code&gt;user&lt;/code&gt;）和订单表（&lt;code&gt;order&lt;/code&gt;），查询“有订单的用户及其订单金额”：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;SELECT u.name, o.amount 
FROM user u 
INNER JOIN order o ON u.id = o.user_id;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果仅包含 &lt;code&gt;user&lt;/code&gt; 和 &lt;code&gt;order&lt;/code&gt; 中 &lt;code&gt;user_id&lt;/code&gt; 匹配的行。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E5%B7%A6%E8%BF%9E%E6%8E%A5%EF%BC%88left-join-%2F-left-outer-join%EF%BC%89&#34;&gt;&lt;strong&gt;2. 左连接（LEFT JOIN / LEFT OUTER JOIN）&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​逻辑​&lt;/strong&gt;​：以​&lt;strong&gt;​左表（第一个表）为基准​&lt;/strong&gt;​，返回左表的所有行，无论右表是否有匹配；若右表无匹配，则右表字段用 &lt;code&gt;NULL&lt;/code&gt; 填充。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​特点​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;主表（左表）数据完整保留，适合“需要主表所有数据，关联表可选”的场景（如查询“所有用户，包括无订单的用户”）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;右表无匹配时，结果中右表字段为 &lt;code&gt;NULL&lt;/code&gt;（可通过 &lt;code&gt;COALESCE(o.amount, 0)&lt;/code&gt; 处理）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​示例​&lt;/strong&gt;​：&lt;br&gt;同样查询用户和订单，但需要所有用户（包括无订单的）：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;SELECT u.name, COALESCE(o.amount, 0) AS amount 
FROM user u 
LEFT JOIN order o ON u.id = o.user_id;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果包含 &lt;code&gt;user&lt;/code&gt; 表的所有行，无订单的用户 &lt;code&gt;amount&lt;/code&gt; 为 &lt;code&gt;0&lt;/code&gt;（或 &lt;code&gt;NULL&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E5%85%B6%E4%BB%96%E8%BF%9E%E6%8E%A5%E7%B1%BB%E5%9E%8B%EF%BC%88%E8%A1%A5%E5%85%85%EF%BC%89&#34;&gt;&lt;strong&gt;3. 其他连接类型（补充）&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​右连接（RIGHT JOIN）​&lt;/strong&gt;​：与左连接相反，以右表为基准保留所有行（实际使用较少，可通过调整主表位置用左连接替代）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​全连接（FULL JOIN）​&lt;/strong&gt;​：MySQL 不直接支持，需通过 &lt;code&gt;LEFT JOIN UNION RIGHT JOIN&lt;/code&gt; 模拟，返回左右表所有行（无匹配时用 &lt;code&gt;NULL&lt;/code&gt; 填充）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%B8%89%E3%80%81%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8%E4%B8%AD%E7%9A%84%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9&#34;&gt;&lt;strong&gt;三、实际应用中的注意事项&lt;/strong&gt;&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​关联条件的位置​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;ON&lt;/code&gt; 子句：定义表间关联的核心条件（如 &lt;code&gt;u.id = o.user_id&lt;/code&gt;），在连接时过滤。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;WHERE&lt;/code&gt; 子句：对连接后的结果集进一步过滤（如 &lt;code&gt;o.create_time &amp;gt; &#39;2023-01-01&#39;&lt;/code&gt;），在连接后过滤。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​避免笛卡尔积​&lt;/strong&gt;​：&lt;br&gt;若忘记写 &lt;code&gt;ON&lt;/code&gt; 子句（或 &lt;code&gt;WHERE&lt;/code&gt; 条件错误），会导致两表所有行两两组合（笛卡尔积），结果数据量爆炸（如 1000 行 × 1000 行 = 100 万行）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​性能优化​&lt;/strong&gt;​：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;连接字段建议添加索引（如 &lt;code&gt;user.id&lt;/code&gt; 和 &lt;code&gt;order.user_id&lt;/code&gt;），否则大表连接会非常慢。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;大表连接时，优先过滤数据量小的表（减少参与连接的行数）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3 style=&#34;&#34; id=&#34;%E6%80%BB%E7%BB%93&#34;&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​内连接​&lt;/strong&gt;​：只保留两表关联字段匹配的行，适合“需要关联表存在数据”的场景。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​左连接​&lt;/strong&gt;​：保留左表所有行，右表无匹配时用 &lt;code&gt;NULL&lt;/code&gt; 填充，适合“需要主表完整数据”的场景。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;解决连表问题的关键是：明确业务需求 → 选择连接类型 → 定义关联条件 → 处理结果中的 &lt;code&gt;NULL&lt;/code&gt; 或重复数据。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>RabbitMQ的架构</title>
        <link>https://qiuyingtyan.top/p/rabbitmqde-jia-gou/</link>
        <pubDate>Sun, 29 Jun 2025 16:58:05 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/rabbitmqde-jia-gou/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/%E5%AE%89%E8%A3%85%E5%BA%94%E7%94%A8.webp" alt="Featured image of post RabbitMQ的架构" /&gt;&lt;h2 style=&#34;&#34; id=&#34;%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84%E4%BD%8D%E7%BD%AE&#34;&gt;&lt;strong&gt;整体架构位置&lt;/strong&gt;&lt;/h2&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;RabbitMQ 在项目中作为消息中间件，主要负责处理​&lt;strong&gt;​短信发送任务队列​&lt;/strong&gt;​，实现异步处理和流量削峰。&lt;/p&gt;&lt;h2 style=&#34;&#34; id=&#34;%E6%A0%B8%E5%BF%83%E7%BB%84%E4%BB%B6&#34;&gt;&lt;strong&gt;核心组件&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​生产者(Producer)​&lt;/strong&gt;​:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;位于服务端应用中&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当系统需要发送短信时，将短信任务封装后发送到RabbitMQ&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​队列(Queue)​&lt;/strong&gt;​:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;创建专用的短信发送队列&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;设置适当的消息持久化策略&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;可能配置死信队列处理发送失败的短信&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​消费者(Consumer)​&lt;/strong&gt;​:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;独立的监听器组件负责消费队列中的短信任务&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;实现重试机制处理发送失败的短信&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;采用批量处理提高效率&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&#34;&#34; id=&#34;%E6%B6%88%E6%81%AF%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B&#34;&gt;&lt;strong&gt;消息处理流程&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务端产生短信发送需求&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;将短信任务序列化为JSON格式&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;发送到RabbitMQ的指定交换器&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;交换器将消息路由到特定队列&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;监听器从队列获取消息&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;调用短信网关API发送短信&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;处理发送结果，记录日志&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&#34;&#34; id=&#34;%E5%85%B3%E9%94%AE%E9%85%8D%E7%BD%AE&#34;&gt;&lt;strong&gt;关键配置&lt;/strong&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​消息持久化​&lt;/strong&gt;​: 确保重启后未处理的消息不丢失&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​确认机制​&lt;/strong&gt;​: 确保消息处理成功后才从队列中删除&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​流量控制​&lt;/strong&gt;​: 通过队列长度限制防止内存溢出&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​死信处理​&lt;/strong&gt;​: 对失败消息进行特殊处理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​并发控制​&lt;/strong&gt;​: 限制同时处理消息的数量&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&#34;&#34; id=&#34;%E6%9E%B6%E6%9E%84%E4%BC%98%E5%8A%BF&#34;&gt;&lt;strong&gt;架构优势&lt;/strong&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​解耦​&lt;/strong&gt;​: 短信发送逻辑与主业务逻辑分离&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​异步​&lt;/strong&gt;​: 非阻塞方式处理短信发送&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​削峰​&lt;/strong&gt;​: 缓冲突发的大量短信发送请求&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​可靠​&lt;/strong&gt;​: 确保短信发送任务不会因服务重启而丢失&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>监控数据是怎么获取推送到前端的？</title>
        <link>https://qiuyingtyan.top/p/jian-kong-shu-ju-shi-zen-me-huo-qu-tui-song-dao-qian-duan-de/</link>
        <pubDate>Sun, 29 Jun 2025 16:55:57 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/jian-kong-shu-ju-shi-zen-me-huo-qu-tui-song-dao-qian-duan-de/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/92793694_p0_master1200.webp" alt="Featured image of post 监控数据是怎么获取推送到前端的？" /&gt;&lt;h2 style=&#34;&#34; id=&#34;1.-%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86%E4%B8%8E%E4%B8%8A%E6%8A%A5&#34;&gt;&lt;strong&gt;1. 客户端数据采集与上报&lt;/strong&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用​&lt;strong&gt;​oshi框架​&lt;/strong&gt;​实时采集监控主机的硬件和系统数据（CPU、内存、磁盘等）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;通过​&lt;strong&gt;​Spring Quartz​&lt;/strong&gt;​定时任务定期（如每30秒）收集数据&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;采集的数据以JSON格式存储了服务端连接信息&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;采用​&lt;strong&gt;​HTTP请求​&lt;/strong&gt;​将监控数据上报到服务端&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&#34;&#34; id=&#34;2.-%E6%9C%8D%E5%8A%A1%E7%AB%AF%E6%95%B0%E6%8D%AE%E5%A4%84%E7%90%86%E4%B8%8E%E5%AD%98%E5%82%A8&#34;&gt;&lt;strong&gt;2. 服务端数据处理与存储&lt;/strong&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务端接收客户端上报的监控数据&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;将数据存入​&lt;strong&gt;​InfluxDB​&lt;/strong&gt;​时序数据库（高效存储时间序列监控数据）&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用​&lt;strong&gt;​Redis​&lt;/strong&gt;​进行缓存优化，提高数据获取效率&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2 style=&#34;&#34; id=&#34;3.-%E5%89%8D%E7%AB%AF%E6%95%B0%E6%8D%AE%E8%8E%B7%E5%8F%96%E4%B8%8E%E5%B1%95%E7%A4%BA&#34;&gt;&lt;strong&gt;3. 前端数据获取与展示&lt;/strong&gt;&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​WebSocket连接​&lt;/strong&gt;​：服务端与前端建立WebSocket连接&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​实时推送​&lt;/strong&gt;​：当有新的监控数据时，服务端主动通过WebSocket推送到前端&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​图表渲染​&lt;/strong&gt;​：前端接收到数据后，使用图表库（可能是ECharts等）实时更新监控数据图表&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​历史查询​&lt;/strong&gt;​：前端也可通过API从InfluxDB获取历史数据进行展示&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>项目中遇到的困难和难点是怎么解决的？</title>
        <link>https://qiuyingtyan.top/p/xiang-mu-zhong-yu-dao-de-kun-nan-he-nan-dian-shi-zen-me-jie-jue-de/</link>
        <pubDate>Sun, 29 Jun 2025 16:54:17 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/xiang-mu-zhong-yu-dao-de-kun-nan-he-nan-dian-shi-zen-me-jie-jue-de/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/93438097_p0_master1200.webp" alt="Featured image of post 项目中遇到的困难和难点是怎么解决的？" /&gt;&lt;h2 style=&#34;&#34; id=&#34;%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%BC%80%E5%8F%91%E9%9A%BE%E7%82%B9&#34;&gt;&lt;strong&gt;客户端开发难点&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​跨平台数据采集​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：不同操作系统硬件数据采集方式不同&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：使用Oshi框架实现跨平台硬件监控，针对不同操作系统封装统一的接口调用方式&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​定时任务可靠性​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：确保定时任务在客户端重启或异常关闭后能恢复&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：利用Spring Quartz持久化任务配置到数据库，结合客户端启动时的任务恢复机制&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​安全连接信息存储​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：注册信息与连接信息需要安全存储&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：JSON配置文件加密存储，关键信息加密处理&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&#34;&#34; id=&#34;%E6%9C%8D%E5%8A%A1%E7%AB%AF%E5%BC%80%E5%8F%91%E9%9A%BE%E7%82%B9&#34;&gt;&lt;strong&gt;服务端开发难点&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​实时数据处理与展示​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：监控数据量大，前端图表需要平滑更新&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：使用InfluxDB时序数据库优化存储与查询效率，设计合理的数据保留策略&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​WebSocket连接管理​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：大量客户端连接时的性能与断线重连问题&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：实现WebSocket心跳检测机制，结合Redis记录连接状态，优化连接池配置&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​权限控制与多账户管理​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：不同账户对不同服务器的权限控制&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：基于Spring Security + JWT实现细粒度权限控制，设计角色-权限-资源的多层关联模型&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​高并发请求处理​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：大量客户端上报数据导致接口压力&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：Redis实现接口限流，消息队列(RabbitMQ)异步处理非实时任务，优化数据库批量写入策略&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​分布式系统跟踪​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：分布式环境下请求链路追踪困难&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：自定义雪花ID生成器，通过过滤器在请求入口生成唯一ID并传递至整个调用链&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&#34;&#34; id=&#34;%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91%E9%9A%BE%E7%82%B9&#34;&gt;&lt;strong&gt;前端开发难点&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​实时数据可视化​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：大量数据点的高效渲染与实时更新&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：ECharts按需渲染和数据采样，结合WebSocket实现数据推送而非轮询&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​伪终端交互体验​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：Web端SSH操作的流畅性与一致性&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：Xterm.js结合WebSocket实现全功能终端模拟，添加输入缓冲和命令缓存机制&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​响应式设计与暗黑模式​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：复杂UI组件在暗黑模式下的样式适配&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：基于CSS变量实现主题切换，Element Plus按需定制主题&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​前端性能优化​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：多标签页和复杂图表导致的内存占用高&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：路由懒加载，组件按需引入，合理使用keep-alive缓存组件状态&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h2 style=&#34;&#34; id=&#34;%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E9%9A%BE%E7%82%B9&#34;&gt;&lt;strong&gt;系统架构难点&lt;/strong&gt;&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​服务间通信与解耦​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：多服务间通信复杂，需要保证消息可靠传递&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：RabbitMQ实现异步通信和解耦，支持消息持久化和失败重试&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​多环境配置管理​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：开发、测试、生产环境的差异化配置管理&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：Spring Profile结合外部配置中心，实现一键环境切换&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;​&lt;strong&gt;​日志收集与分析​&lt;/strong&gt;​&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;问题&lt;/em&gt;：分布式系统中日志分散，问题定位困难&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;em&gt;解决方案&lt;/em&gt;：统一日志格式(包含雪花ID)，ELK收集分析，支持请求链路追踪&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>个人面经</title>
        <link>https://qiuyingtyan.top/%E9%9D%A2%E7%BB%8F/</link>
        <pubDate>Sun, 29 Jun 2025 16:33:58 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/%E9%9D%A2%E7%BB%8F/</guid>
        <description>&lt;h1 style=&#34;&#34; id=&#34;%E6%9F%8F%E7%A0%81%E9%A1%B9%E7%9B%AE%E9%9D%A2%E7%BB%8F%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 36px&#34;&gt;&lt;strong&gt;柏码项目面经：&lt;/strong&gt;&lt;/span&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/ru-he-shi-xian-sshlian-jie-he-lei-si-xshellye-mian/&#34;&gt;如何实现ssh连接和类似xshell页面？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/xiang-mu-zhong-yu-dao-de-kun-nan-he-nan-dian-shi-zen-me-jie-jue-de/&#34;&gt;项目中遇到的困难和难点是怎么解决的？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/jian-kong-shu-ju-shi-zen-me-huo-qu-tui-song-dao-qian-duan-de/&#34;&gt;监控数据是怎么获取推送到前端的？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/websocketzen-me-xie-de/&#34;&gt;websocket怎么写的？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/rbacshi-zen-me-xie-de/&#34;&gt;rbac是怎么写的？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%B6%E5%AE%83%E9%97%AE%E9%A2%98%EF%BC%9A&#34;&gt;其它问题：&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/rabbitmqde-jia-gou/&#34;&gt;RabbitMQ的架构|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/mysql-lianbiao-lianjie/&#34;&gt;MySQL中连表的问题是怎么解决的？左连接内连接之类的区别是什么？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/httphe-websockettong-xin-de-qu-bie/&#34;&gt;Http和WebSocket通信的区别|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/udphe-tcpde-qu-bie/&#34;&gt;UDP和TCP的区别|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/shu-ru-wang-zhi-hou-ye-mian-xian-shi-de-liu-cheng-shi-shi-me/&#34;&gt;输入网址后页面显示的流程是什么？|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/wei-shi-me-yao-qian-hou-duan-fen-chi/&#34;&gt;为什么要前后端分离|秋萤blog&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://qiuyingtyan.top/p/vuewei-shi-me-shi-jsxie-de-er-bu-shi-qi-ta-yu-yan-xie-de/&#34;&gt;Vue为什么是js写的而不是其它语言写的？|秋萤blog&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>如何实现ssh连接和类似xshell页面？</title>
        <link>https://qiuyingtyan.top/p/ru-he-shi-xian-sshlian-jie-he-lei-si-xshellye-mian/</link>
        <pubDate>Wed, 05 Mar 2025 16:09:58 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/ru-he-shi-xian-sshlian-jie-he-lei-si-xshellye-mian/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/86432139_p0_master1200.webp" alt="Featured image of post 如何实现ssh连接和类似xshell页面？" /&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 16px; color: rgba(0, 0, 0, 0.9)&#34;&gt;项目中 SSH 连接与类似 Xshell 页面的实现主要依赖 ​&lt;/span&gt;&lt;strong&gt;​服务端 JSCH 框架​&lt;/strong&gt;&lt;span style=&#34;font-size: 16px; color: rgba(0, 0, 0, 0.9)&#34;&gt;​ 和 ​&lt;/span&gt;&lt;strong&gt;​前端 Xterm.js 组件​&lt;/strong&gt;&lt;span style=&#34;font-size: 16px; color: rgba(0, 0, 0, 0.9)&#34;&gt;​，结合 WebSocket 实现实时交互。&lt;/span&gt;&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;%E4%B8%80%E3%80%81ssh-%E8%BF%9E%E6%8E%A5%E7%9A%84%E6%A0%B8%E5%BF%83%E5%AE%9E%E7%8E%B0%EF%BC%88%E6%9C%8D%E5%8A%A1%E7%AB%AF%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;一、SSH 连接的核心实现（服务端）​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;服务端通过 ​&lt;strong&gt;​JSCH（Java SSH2 客户端库）​&lt;/strong&gt;​ 建立与目标服务器的 SSH 连接，负责执行命令、获取输出，并将结果返回前端。关键流程如下：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8Bssh-%E8%BF%9E%E6%8E%A5%E5%BB%BA%E7%AB%8B%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​SSH 连接建立​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​触发条件​&lt;/strong&gt;​：前端用户在 Xshell 页面输入命令（如 &lt;code&gt;ssh user@host&lt;/code&gt;）并提交，或直接通过页面发起对某台服务器的管理请求。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​服务端处理​&lt;/strong&gt;​：&lt;br&gt;服务端接收前端通过 WebSocket 发送的 SSH 连接请求（包含目标服务器 IP、端口、用户名、密码/密钥等信息）。&lt;br&gt;使用 JSCH 创建 &lt;code&gt;Session&lt;/code&gt; 对象，配置连接参数（如超时时间、加密算法），并通过 &lt;code&gt;session.connect()&lt;/code&gt; 建立到目标服务器的 SSH 连接。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E4%B8%8E%E8%BE%93%E5%87%BA%E8%8E%B7%E5%8F%96%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​命令执行与输出获取​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​命令传递​&lt;/strong&gt;​：前端用户在 Xterm 页面输入命令（如 &lt;code&gt;ls -l&lt;/code&gt;），通过 WebSocket 发送到服务端。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​命令执行​&lt;/strong&gt;​：服务端通过 JSCH 的 &lt;code&gt;ChannelExec&lt;/code&gt; 或 &lt;code&gt;ChannelShell&lt;/code&gt; 通道，将命令发送到目标服务器执行。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;若为交互式命令（如需要持续输入的 &lt;code&gt;top&lt;/code&gt;），使用 &lt;code&gt;ChannelShell&lt;/code&gt; 保持长连接，持续接收输出；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;若为单条命令（如 &lt;code&gt;df -h&lt;/code&gt;），使用 &lt;code&gt;ChannelExec&lt;/code&gt; 执行后关闭通道。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​输出捕获​&lt;/strong&gt;​：通过 &lt;code&gt;channel.setOutputStream()&lt;/code&gt; 或 &lt;code&gt;channel.setErrStream()&lt;/code&gt; 捕获命令的标准输出和错误输出，存储为字符串或字节数组。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E7%BB%93%E6%9E%9C%E8%BF%94%E5%9B%9E%E5%89%8D%E7%AB%AF%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​结果返回前端​​&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;服务端将捕获的输出通过 WebSocket 实时推送回前端，前端 Xterm.js 将输出渲染到终端界面，完成一次完整的“输入-执行-输出”闭环。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%BA%8C%E3%80%81%E7%B1%BB%E4%BC%BC-xshell-%E9%A1%B5%E9%9D%A2%E7%9A%84%E5%AE%9E%E7%8E%B0%EF%BC%88%E5%89%8D%E7%AB%AF%EF%BC%89%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​二、类似 Xshell 页面的实现（前端）​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;前端通过 ​&lt;strong&gt;​Xterm.js​&lt;/strong&gt;​ 模拟终端界面，结合 WebSocket 与服务端实时交互，实现类 Xshell 的操作体验。关键功能如下：&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E2%80%8B%E2%80%8B%E7%BB%88%E7%AB%AF%E7%95%8C%E9%9D%A2%E6%B8%B2%E6%9F%93%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;1. ​​终端界面渲染​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​Xterm.js 初始化​&lt;/strong&gt;​：在前端页面（如 Vue 组件）中初始化 Xterm.js 实例，配置终端参数（如行高、字体、主题色、光标样式）。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;import { Terminal } from &#39;xterm&#39;;
import { FitAddon } from &#39;xterm-addon-fit&#39;;
&lt;p&gt;// 初始化终端
const term = new Terminal({
cursorBlink: true,
theme: { background: &amp;lsquo;#1E1E1E&amp;rsquo;, foreground: &amp;lsquo;#FFFFFF&amp;rsquo; },
fontSize: 14,
fontFamily: &amp;lsquo;Menlo, Monaco, &amp;ldquo;Courier New&amp;rdquo;, monospace&amp;rsquo;
});
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
term.open(document.getElementById(&amp;lsquo;ssh-terminal&amp;rsquo;)); // 挂载到 DOM
fitAddon.fit(); // 自适应容器大小&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​ANSI 转义序列支持​&lt;/strong&gt;​：Xterm.js 内置解析 ANSI 转义码（如颜色 &lt;code&gt;\033[31m&lt;/code&gt;、光标移动 &lt;code&gt;\033[1A&lt;/code&gt;、清屏 &lt;code&gt;\033[2J&lt;/code&gt;），能正确渲染远程服务器的输出（如命令提示符、进度条、错误信息）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E2%80%8B%E2%80%8B%E7%94%A8%E6%88%B7%E8%BE%93%E5%85%A5%E4%B8%8E%E5%AE%9E%E6%97%B6%E4%BA%A4%E4%BA%92%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;2. ​​用户输入与实时交互​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​输入监听​&lt;/strong&gt;​：监听终端的 &lt;code&gt;onData&lt;/code&gt; 事件，捕获用户输入的字符（包括组合键如 &lt;code&gt;Ctrl+C&lt;/code&gt;、&lt;code&gt;Tab&lt;/code&gt; 补全）。&lt;/p&gt;&lt;pre&gt;&lt;code&gt;term.onData(data =&amp;gt; {
// 通过 WebSocket 发送用户输入到服务端
websocket.send(JSON.stringify({ type: &amp;lsquo;ssh-command&amp;rsquo;, data }));
});&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​实时输出显示​&lt;/strong&gt;​：服务端通过 WebSocket 推送输出数据时，前端调用 &lt;code&gt;term.write(output)&lt;/code&gt; 将内容写入终端，模拟真实终端的逐行/逐字符显示效果。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E2%80%8B%E2%80%8B%E4%BC%9A%E8%AF%9D%E7%AE%A1%E7%90%86%E4%B8%8E%E7%8A%B6%E6%80%81%E4%BF%9D%E6%8C%81%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;3. ​​会话管理与状态保持​​&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​长连接支持​&lt;/strong&gt;​：使用 WebSocket 维持前端与服务端的持久连接，确保长时间运行的命令（如 &lt;code&gt;top&lt;/code&gt;、&lt;code&gt;tail -f&lt;/code&gt;）输出能实时刷新。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​会话断开处理​&lt;/strong&gt;​：若 WebSocket 连接中断（如网络波动），前端提示用户重新连接；服务端检测到连接断开后，关闭对应的 JSCH &lt;code&gt;Session&lt;/code&gt; 释放资源。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E4%B8%89%E3%80%81%E5%89%8D%E5%90%8E%E7%AB%AF%E5%8D%8F%E5%90%8C%E6%B5%81%E7%A8%8B%E6%80%BB%E7%BB%93%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​三、前后端协同流程总结​​&lt;/strong&gt;&lt;/h3&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;整个 SSH 交互流程可简化为以下步骤：&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;用户在前端 Xterm 页面输入命令（如 &lt;code&gt;ssh root@192.168.1.100&lt;/code&gt;）并回车；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端通过 WebSocket 将命令发送至服务端；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务端使用 JSCH 解析命令，建立与目标服务器的 SSH 连接；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务端执行命令（或传递到目标服务器执行），捕获输出；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;服务端将输出通过 WebSocket 实时推送回前端；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;前端 Xterm.js 渲染输出，用户看到命令执行结果；&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;重复步骤 1-6，完成交互式操作。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h3 style=&#34;&#34; id=&#34;%E2%80%8B%E2%80%8B%E5%9B%9B%E3%80%81%E5%85%B3%E9%94%AE%E6%8A%80%E6%9C%AF%E7%82%B9%E8%A1%A5%E5%85%85%E2%80%8B%E2%80%8B&#34;&gt;&lt;strong&gt;​​四、关键技术点补充​​&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​权限控制​&lt;/strong&gt;​：服务端通过 SpringSecurity + JWT 校验用户身份，结合子账户权限配置（如限制某些用户仅能访问特定服务器），确保 SSH 操作的安全性。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​连接复用​&lt;/strong&gt;​：服务端缓存活跃的 SSH &lt;code&gt;Session&lt;/code&gt;（如通过 Redis 存储会话 ID 与 &lt;code&gt;Session&lt;/code&gt; 对象的映射），避免频繁创建/销毁连接带来的性能损耗。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;​&lt;strong&gt;​异常处理​&lt;/strong&gt;​：服务端捕获 JSCH 异常（如连接超时、认证失败），通过 WebSocket 返回结构化错误信息（如 &lt;code&gt;{ code: 401, msg: &amp;ldquo;认证失败&amp;rdquo; }&lt;/code&gt;），前端统一处理并提示用户。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;line-height: 1.75&#34;&gt;综上，你的项目通过 ​&lt;strong&gt;​服务端 JSCH 实现 SSH 连接与命令执行​&lt;/strong&gt;​，结合 ​&lt;strong&gt;​前端 Xterm.js 模拟终端界面​&lt;/strong&gt;​ 和 ​&lt;strong&gt;​WebSocket 实时通信​&lt;/strong&gt;​，最终实现了类似 Xshell 的交互式 SSH 管理功能。&lt;/p&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Maven的入门和使用</title>
        <link>https://qiuyingtyan.top/p/maven/</link>
        <pubDate>Fri, 22 Nov 2024 16:44:00 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/maven/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/123125006_p0_master1200.webp" alt="Featured image of post Maven的入门和使用" /&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%B8%80%E3%80%81%E4%BB%80%E4%B9%88%E6%98%AFmaven%EF%BC%9F&#34;&gt;一、什么是Maven？&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;Maven 是一个流行的&lt;strong&gt;项目管理工具&lt;/strong&gt;和构建工具，可以对 Java 项目进行&lt;strong&gt;构建&lt;/strong&gt;、&lt;strong&gt;依赖管理&lt;/strong&gt;。简单来说，它就像一个“助手”，使得项目的开发和管理变得更加简单和高效。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;其它知识点补充：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;项目管理工具：&lt;/strong&gt;指的是一种软件，帮助开发者组织、管理和跟踪项目的进展。使用 Maven，可以轻松创建、配置和维护 Java 项目。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;构建&lt;/strong&gt;：是指将源代码转换为可以运行的程序的过程。Maven 可以自动化这个过程，它会根据指定的配置文件（通常是 &lt;code&gt;pom.xml&lt;/code&gt;）来编译代码、打包程序、运行测试等。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;：是指处理项目中使用的库或其他组件（称为依赖）的过程。很多 Java 项目会依赖于其他库来实现某些功能。Maven 可以自动下载这些依赖，并确保它们的版本兼容，这样开发者就不需要手动管理这些库的版本和下载。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%8C%E3%80%81maven%E6%9C%89%E4%BB%80%E4%B9%88%E7%94%A8%EF%BC%9F%E6%88%91%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%AD%A6maven%EF%BC%9F&#34;&gt;二、Maven有什么用？我们为什么要学Maven？&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E6%9C%89%E4%BB%80%E4%B9%88%E7%94%A8&#34;&gt;Maven 有什么用&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目的自动构建，包括代码的编译、测试、打包、安装、部署等操作。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;依赖管理，项目使用到哪些依赖，可以快速完成导入，不需要手动导入jar包。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;%E6%88%91%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%AD%A6-maven%EF%BC%9F&#34;&gt;我们为什么要学 Maven？&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;简单一句话，你不学maven就别想学别的东西(例如springcloud)！&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%B8%89%E3%80%81maven%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84&#34;&gt;三、Maven项目结构&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/Maven%E9%A1%B9%E7%9B%AE%E7%BB%93%E6%9E%84.webp&#34; alt=&#34;Maven项目结构.jpg&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;而下面的pom.xml则是Maven的核心配置，也是整个项目的所有依赖、插件、以及各种配置的集合，它也是使用XML格式编写的，一个标准的pom配置长这样：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&amp;gt;
&amp;lt;project xmlns=&#34;http://maven.apache.org/POM/4.0.0&#34;
         xmlns:xsi=&#34;http://www.w3.org/2001/XMLSchema-instance&#34;
         xsi:schemaLocation=&#34;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89&#34;&gt;&lt;code&gt;2. scope（重点）&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%AD%E3%80%81maven%E5%AE%89%E8%A3%85%E3%80%81%E5%8F%AF%E9%80%89%E5%92%8C%E6%8E%92%E9%99%A4&#34;&gt;&lt;strong&gt;六、Maven安装、可选和排除&lt;/strong&gt;&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;1%E3%80%81maven-%E5%AE%89%E8%A3%85&#34;&gt;1、Maven 安装&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;问题导入：如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢？&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个用于测试的简单项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&amp;ldquo;1.0&amp;rdquo; encoding=&amp;ldquo;UTF-8&amp;rdquo;?&amp;gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;TestMaven&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0-SNAPSHOT&amp;amp;lt;/version&amp;amp;gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class TestUtils {
public static void test() {
System.out.println(&amp;ldquo;家人们谁懂啊，蒸虾头，怎么会有人想吃我家鸽鸽下的蛋&amp;rdquo;);
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;接着我们点击右上角的Maven选项，然后执行&lt;code&gt;install&lt;/code&gt;或直接在命令行中输入&lt;code&gt;mvn install&lt;/code&gt;来安装我们自己的项目到本地Maven仓库中。&lt;/p&gt;&lt;p style=&#34;line-height: 1.6&#34;&gt;接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了，只需要填写和这边一样的坐标：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.test&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;TestMaven&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;接着我们就可以在项目中直接使用了：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
TestUtils.test();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;2%E3%80%81maven-%E4%B8%AD%E7%9A%84%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96%EF%BC%88optional%EF%BC%89&#34;&gt;2、Maven 中的可选依赖（Optional）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Maven 的可选依赖属性 &lt;code&gt;optional&lt;/code&gt; 用于标记某个依赖是否是&lt;strong&gt;可选的&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：Maven 会传递所有依赖的依赖（传递性依赖），即如果项目 A 依赖项目 B，而项目 B 又依赖项目 C，则项目 A 会默认获取 B 和 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;optional&lt;/code&gt; 可以避免这种传递性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当某个依赖是额外的功能模块，而下游项目可能不需要它时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;避免引入无用的依赖，减少构建时间和冲突风险。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，项目 B 依赖项目 C：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;项目 B 中声明 C 为可选依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果：项目 A 不会自动获取 C，除非手动添加。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;3%E3%80%81maven-%E4%B8%AD%E7%9A%84%E4%BE%9D%E8%B5%96%E6%8E%92%E9%99%A4%EF%BC%88exclusions%EF%BC%89&#34;&gt;3、Maven 中的依赖排除（Exclusions）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;排除传递性依赖中不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;为什么需要？&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;防止依赖冲突（例如不同版本的库）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;删除多余的依赖以优化项目构建。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，而项目 B 又依赖项目 C，但项目 A 不需要 C。&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;传递性依赖的层级示例&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目 A -&amp;gt; 项目 B -&amp;gt; 项目 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果不需要项目 C，可通过 &lt;code&gt;exclusions&lt;/code&gt; 将其排除，最终 A 只包含 B。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;常见问题解决&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖冲突&lt;/strong&gt;：当传递性依赖中某个库的多个版本引入冲突时，排除旧版本并手动引入所需版本。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;避免不必要的依赖&lt;/strong&gt;：减少构建体积，避免不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E7%9A%84%E7%BB%A7%E6%89%BF&#34;&gt;&lt;strong&gt;Maven的继承&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;Maven 的继承机制允许项目的 POM 文件继承另一个 POM 文件中的配置，从而避免重复定义相同的配置。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-%E7%BB%A7%E6%89%BF%E7%9A%84%E7%89%B9%E7%82%B9&#34;&gt;1. 继承的特点&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;层级结构&lt;/strong&gt;：Maven 的继承是树状结构，一个子项目只能继承一个父项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;统一管理&lt;/strong&gt;：父 POM 通常定义通用的依赖、插件、构建配置等，子 POM 自动继承。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;减少重复&lt;/strong&gt;：多个子项目可以共享父 POM 中的配置，提高复用性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-%E7%88%B6-pom-%E5%AE%9A%E4%B9%89&#34;&gt;2. 父 POM 定义&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;父 POM 中定义通用配置，例如：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;x&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-%E5%AD%90%E9%A1%B9%E7%9B%AE%E7%BB%A7%E6%89%BF&#34;&gt;3. 子项目继承&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;子项目通过 &lt;code&gt;&amp;lt;parent&amp;gt;&lt;/code&gt; 标签指定父 POM：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;x&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;子项目继承父 POM 的依赖管理和插件配置。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;可在子项目中覆盖或补充父 POM 的配置。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;多模块机制用于将一个大项目拆分为多个模块，每个模块都是一个独立的 Maven 项目，但可以共享配置和依赖。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E7%9A%84%E5%A4%9A%E6%A8%A1%E5%9D%97&#34;&gt;Maven的多模块&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-%E5%A4%9A%E6%A8%A1%E5%9D%97%E7%BB%93%E6%9E%84&#34;&gt;1. 多模块结构&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;多模块项目通常有一个父 POM 和多个子模块，目录结构如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34;&gt;project-root/
├── pom.xml          # 父 POM
├── module-a/        # 子模块 A
│   └── pom.xml
├── module-b/        # 子模块 B
│   └── pom.xml&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-%E7%88%B6-pom%EF%BC%88%E6%A0%B9-pom%EF%BC%89&#34;&gt;2. 父 POM（根 POM）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;父 POM 除了继承机制的配置外，还需要声明模块：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;project&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;multi-module-project&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt; &amp;lt;!&amp;ndash; 必须是 pom 类型 &amp;ndash;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;modules&amp;amp;gt;
    &amp;amp;lt;module&amp;amp;gt;module-a&amp;amp;lt;/module&amp;amp;gt;
    &amp;amp;lt;module&amp;amp;gt;module-b&amp;amp;lt;/module&amp;amp;gt;
&amp;amp;lt;/modules&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-%E5%AD%90%E6%A8%A1%E5%9D%97%E7%9A%84-pom&#34;&gt;3. 子模块的 POM&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;子模块 POM 需要指定父项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;project&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&amp;lt;parent&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;multi-module-project&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/parent&amp;gt;
&amp;lt;artifactId&amp;gt;module-a&amp;lt;/artifactId&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-%E6%9E%84%E5%BB%BA%E5%92%8C%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86&#34;&gt;4. 构建和依赖管理&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;构建&lt;/strong&gt;：在根目录运行 &lt;code&gt;mvn install&lt;/code&gt;，会依次构建所有模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;：模块之间可以互相依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;module-a&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;5.-%E4%BC%98%E5%8A%BF&#34;&gt;5. 优势&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;模块化&lt;/strong&gt;：每个模块负责单一功能，便于开发和维护。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;共享配置&lt;/strong&gt;：通过父 POM 统一管理版本和插件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;并行构建&lt;/strong&gt;：Maven 可以并行构建多个模块，加快构建速度。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E6%B5%8B%E8%AF%95%E5%92%8C%E6%89%93%E5%8C%85&#34;&gt;Maven测试和打包&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;在 IDEA 中，Maven 项目有多个生命周期，每个生命周期对应一个插件执行任务。常见的命令如下：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;clean&lt;/code&gt;：清理 &lt;code&gt;target&lt;/code&gt; 文件夹，解决缓存问题。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;validate&lt;/code&gt;：验证项目的可用性。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;：编译项目为 &lt;code&gt;.class&lt;/code&gt; 文件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;install&lt;/code&gt;：将项目安装到本地仓库，供其他项目作为依赖使用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;verify&lt;/code&gt;：依次执行 &lt;code&gt;validate&lt;/code&gt;、&lt;code&gt;compile&lt;/code&gt;、&lt;code&gt;package&lt;/code&gt; 等生命周期阶段。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;每个命令执行完后，IDE 会显示 &lt;code&gt;BUILD SUCCESS&lt;/code&gt;，如果出现错误则会显示详细信息。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E6%B5%8B%E8%AF%95%E5%91%BD%E4%BB%A4&#34;&gt;1. 测试命令&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;通过 &lt;code&gt;test&lt;/code&gt; 命令，Maven 会自动运行 &lt;code&gt;test&lt;/code&gt; 目录下的所有测试案例。测试类的名称需要以 &lt;code&gt;Test&lt;/code&gt; 结尾（例如 &lt;code&gt;MainTest&lt;/code&gt;），测试方法必须标注 &lt;code&gt;@Test&lt;/code&gt; 注解。示例如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class MainTest {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Test
public void test() {
    System.out.println(&amp;quot;我测你码&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E6%89%93%E5%8C%85%E5%91%BD%E4%BB%A4&#34;&gt;2. 打包命令&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;package&lt;/code&gt; 命令可以将项目打包成 JAR 文件，生成的 JAR 文件可以作为其他项目的依赖或可执行文件。执行 &lt;code&gt;package&lt;/code&gt; 时，会先自动执行测试命令，确保项目没有问题。如果希望跳过测试，可以使用以下命令：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mvn package -Dmaven.test.skip=true&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E6%89%93%E5%8C%85%E5%B8%A6%E4%BE%9D%E8%B5%96%E7%9A%84-jar-%E6%96%87%E4%BB%B6&#34;&gt;3. 打包带依赖的 JAR 文件&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;通常，打包后的 JAR 文件仅包含项目自己的类，而缺少所需的外部依赖。如果要将项目及其依赖一起打包，可以使用 &lt;code&gt;maven-assembly-plugin&lt;/code&gt; 插件。插件配置如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;plugin&amp;gt;
&amp;lt;artifactId&amp;gt;maven-assembly-plugin&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
&amp;lt;configuration&amp;gt;
&amp;lt;descriptorRefs&amp;gt;
&amp;lt;descriptorRef&amp;gt;jar-with-dependencies&amp;lt;/descriptorRef&amp;gt;
&amp;lt;/descriptorRefs&amp;gt;
&amp;lt;archive&amp;gt;
&amp;lt;manifest&amp;gt;
&amp;lt;addClasspath&amp;gt;true&amp;lt;/addClasspath&amp;gt;
&amp;lt;mainClass&amp;gt;com.test.Main&amp;lt;/mainClass&amp;gt;
&amp;lt;/manifest&amp;gt;
&amp;lt;/archive&amp;gt;
&amp;lt;/configuration&amp;gt;
&amp;lt;executions&amp;gt;
&amp;lt;execution&amp;gt;
&amp;lt;id&amp;gt;make-assembly&amp;lt;/id&amp;gt;
&amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;
&amp;lt;goals&amp;gt;
&amp;lt;goal&amp;gt;single&amp;lt;/goal&amp;gt;
&amp;lt;/goals&amp;gt;
&amp;lt;/execution&amp;gt;
&amp;lt;/executions&amp;gt;
&amp;lt;/plugin&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;配置好后，重新执行 &lt;code&gt;package&lt;/code&gt; 命令，最终会生成两个 JAR 文件：一个是普通的 JAR 文件，另一个是包含所有依赖的 JAR 文件。我们只需要执行以下命令即可运行：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;java -jar your-project-jar-with-dependencies.jar&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89&#34;&gt;&lt;code&gt;2. scope（重点）&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%AD%E3%80%81maven%E5%AE%89%E8%A3%85%E3%80%81%E5%8F%AF%E9%80%89%E5%92%8C%E6%8E%92%E9%99%A4&#34;&gt;&lt;strong&gt;六、Maven安装、可选和排除&lt;/strong&gt;&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;1%E3%80%81maven-%E5%AE%89%E8%A3%85&#34;&gt;1、Maven 安装&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;问题导入：如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢？&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个用于测试的简单项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&amp;ldquo;1.0&amp;rdquo; encoding=&amp;ldquo;UTF-8&amp;rdquo;?&amp;gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;TestMaven&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0-SNAPSHOT&amp;amp;lt;/version&amp;amp;gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class TestUtils {
public static void test() {
System.out.println(&amp;ldquo;家人们谁懂啊，蒸虾头，怎么会有人想吃我家鸽鸽下的蛋&amp;rdquo;);
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;接着我们点击右上角的Maven选项，然后执行&lt;code&gt;install&lt;/code&gt;或直接在命令行中输入&lt;code&gt;mvn install&lt;/code&gt;来安装我们自己的项目到本地Maven仓库中。&lt;/p&gt;&lt;p style=&#34;line-height: 1.6&#34;&gt;接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了，只需要填写和这边一样的坐标：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.test&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;TestMaven&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;接着我们就可以在项目中直接使用了：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
TestUtils.test();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;2%E3%80%81maven-%E4%B8%AD%E7%9A%84%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96%EF%BC%88optional%EF%BC%89&#34;&gt;2、Maven 中的可选依赖（Optional）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Maven 的可选依赖属性 &lt;code&gt;optional&lt;/code&gt; 用于标记某个依赖是否是&lt;strong&gt;可选的&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：Maven 会传递所有依赖的依赖（传递性依赖），即如果项目 A 依赖项目 B，而项目 B 又依赖项目 C，则项目 A 会默认获取 B 和 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;optional&lt;/code&gt; 可以避免这种传递性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当某个依赖是额外的功能模块，而下游项目可能不需要它时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;避免引入无用的依赖，减少构建时间和冲突风险。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，项目 B 依赖项目 C：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;项目 B 中声明 C 为可选依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果：项目 A 不会自动获取 C，除非手动添加。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;3%E3%80%81maven-%E4%B8%AD%E7%9A%84%E4%BE%9D%E8%B5%96%E6%8E%92%E9%99%A4%EF%BC%88exclusions%EF%BC%89&#34;&gt;3、Maven 中的依赖排除（Exclusions）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;排除传递性依赖中不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;为什么需要？&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;防止依赖冲突（例如不同版本的库）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;删除多余的依赖以优化项目构建。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，而项目 B 又依赖项目 C，但项目 A 不需要 C。&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;传递性依赖的层级示例&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目 A -&amp;gt; 项目 B -&amp;gt; 项目 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果不需要项目 C，可通过 &lt;code&gt;exclusions&lt;/code&gt; 将其排除，最终 A 只包含 B。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;常见问题解决&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖冲突&lt;/strong&gt;：当传递性依赖中某个库的多个版本引入冲突时，排除旧版本并手动引入所需版本。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;避免不必要的依赖&lt;/strong&gt;：减少构建体积，避免不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E7%9A%84%E7%BB%A7%E6%89%BF&#34;&gt;&lt;strong&gt;Maven的继承&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;Maven 的继承机制允许项目的 POM 文件继承另一个 POM 文件中的配置，从而避免重复定义相同的配置。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-%E7%BB%A7%E6%89%BF%E7%9A%84%E7%89%B9%E7%82%B9&#34;&gt;1. 继承的特点&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;层级结构&lt;/strong&gt;：Maven 的继承是树状结构，一个子项目只能继承一个父项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;统一管理&lt;/strong&gt;：父 POM 通常定义通用的依赖、插件、构建配置等，子 POM 自动继承。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;减少重复&lt;/strong&gt;：多个子项目可以共享父 POM 中的配置，提高复用性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-%E7%88%B6-pom-%E5%AE%9A%E4%B9%89&#34;&gt;2. 父 POM 定义&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;父 POM 中定义通用配置，例如：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;x&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-%E5%AD%90%E9%A1%B9%E7%9B%AE%E7%BB%A7%E6%89%BF&#34;&gt;3. 子项目继承&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;子项目通过 &lt;code&gt;&amp;lt;parent&amp;gt;&lt;/code&gt; 标签指定父 POM：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;x&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;子项目继承父 POM 的依赖管理和插件配置。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;可在子项目中覆盖或补充父 POM 的配置。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;多模块机制用于将一个大项目拆分为多个模块，每个模块都是一个独立的 Maven 项目，但可以共享配置和依赖。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E7%9A%84%E5%A4%9A%E6%A8%A1%E5%9D%97&#34;&gt;Maven的多模块&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-%E5%A4%9A%E6%A8%A1%E5%9D%97%E7%BB%93%E6%9E%84&#34;&gt;1. 多模块结构&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;多模块项目通常有一个父 POM 和多个子模块，目录结构如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-ruby&#34;&gt;project-root/
├── pom.xml          # 父 POM
├── module-a/        # 子模块 A
│   └── pom.xml
├── module-b/        # 子模块 B
│   └── pom.xml&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-%E7%88%B6-pom%EF%BC%88%E6%A0%B9-pom%EF%BC%89&#34;&gt;2. 父 POM（根 POM）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;父 POM 除了继承机制的配置外，还需要声明模块：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;project&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;multi-module-project&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;packaging&amp;gt;pom&amp;lt;/packaging&amp;gt; &amp;lt;!&amp;ndash; 必须是 pom 类型 &amp;ndash;&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;modules&amp;amp;gt;
    &amp;amp;lt;module&amp;amp;gt;module-a&amp;amp;lt;/module&amp;amp;gt;
    &amp;amp;lt;module&amp;amp;gt;module-b&amp;amp;lt;/module&amp;amp;gt;
&amp;amp;lt;/modules&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-%E5%AD%90%E6%A8%A1%E5%9D%97%E7%9A%84-pom&#34;&gt;3. 子模块的 POM&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;子模块 POM 需要指定父项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;project&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
&amp;lt;parent&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;multi-module-project&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/parent&amp;gt;
&amp;lt;artifactId&amp;gt;module-a&amp;lt;/artifactId&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-%E6%9E%84%E5%BB%BA%E5%92%8C%E4%BE%9D%E8%B5%96%E7%AE%A1%E7%90%86&#34;&gt;4. 构建和依赖管理&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;构建&lt;/strong&gt;：在根目录运行 &lt;code&gt;mvn install&lt;/code&gt;，会依次构建所有模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;：模块之间可以互相依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;module-a&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;5.-%E4%BC%98%E5%8A%BF&#34;&gt;5. 优势&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;模块化&lt;/strong&gt;：每个模块负责单一功能，便于开发和维护。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;共享配置&lt;/strong&gt;：通过父 POM 统一管理版本和插件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;并行构建&lt;/strong&gt;：Maven 可以并行构建多个模块，加快构建速度。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E6%B5%8B%E8%AF%95%E5%92%8C%E6%89%93%E5%8C%85&#34;&gt;Maven测试和打包&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;在 IDEA 中，Maven 项目有多个生命周期，每个生命周期对应一个插件执行任务。常见的命令如下：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;clean&lt;/code&gt;：清理 &lt;code&gt;target&lt;/code&gt; 文件夹，解决缓存问题。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;validate&lt;/code&gt;：验证项目的可用性。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;：编译项目为 &lt;code&gt;.class&lt;/code&gt; 文件。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;install&lt;/code&gt;：将项目安装到本地仓库，供其他项目作为依赖使用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;verify&lt;/code&gt;：依次执行 &lt;code&gt;validate&lt;/code&gt;、&lt;code&gt;compile&lt;/code&gt;、&lt;code&gt;package&lt;/code&gt; 等生命周期阶段。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;每个命令执行完后，IDE 会显示 &lt;code&gt;BUILD SUCCESS&lt;/code&gt;，如果出现错误则会显示详细信息。&lt;/p&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E6%B5%8B%E8%AF%95%E5%91%BD%E4%BB%A4&#34;&gt;1. 测试命令&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;通过 &lt;code&gt;test&lt;/code&gt; 命令，Maven 会自动运行 &lt;code&gt;test&lt;/code&gt; 目录下的所有测试案例。测试类的名称需要以 &lt;code&gt;Test&lt;/code&gt; 结尾（例如 &lt;code&gt;MainTest&lt;/code&gt;），测试方法必须标注 &lt;code&gt;@Test&lt;/code&gt; 注解。示例如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class MainTest {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Test
public void test() {
    System.out.println(&amp;quot;我测你码&amp;quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E6%89%93%E5%8C%85%E5%91%BD%E4%BB%A4&#34;&gt;2. 打包命令&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;package&lt;/code&gt; 命令可以将项目打包成 JAR 文件，生成的 JAR 文件可以作为其他项目的依赖或可执行文件。执行 &lt;code&gt;package&lt;/code&gt; 时，会先自动执行测试命令，确保项目没有问题。如果希望跳过测试，可以使用以下命令：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;mvn package -Dmaven.test.skip=true&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E6%89%93%E5%8C%85%E5%B8%A6%E4%BE%9D%E8%B5%96%E7%9A%84-jar-%E6%96%87%E4%BB%B6&#34;&gt;3. 打包带依赖的 JAR 文件&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;通常，打包后的 JAR 文件仅包含项目自己的类，而缺少所需的外部依赖。如果要将项目及其依赖一起打包，可以使用 &lt;code&gt;maven-assembly-plugin&lt;/code&gt; 插件。插件配置如下：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;x&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;配置好后，重新执行 &lt;code&gt;package&lt;/code&gt; 命令，最终会生成两个 JAR 文件：一个是普通的 JAR 文件，另一个是包含所有依赖的 JAR 文件。我们只需要执行以下命令即可运行：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;b&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89&#34;&gt;&lt;code&gt;2. scope（重点）&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%AD%E3%80%81maven%E5%AE%89%E8%A3%85%E3%80%81%E5%8F%AF%E9%80%89%E5%92%8C%E6%8E%92%E9%99%A4&#34;&gt;&lt;strong&gt;六、Maven安装、可选和排除&lt;/strong&gt;&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E5%AE%89%E8%A3%85&#34;&gt;Maven 安装&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;问题导入：如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢？&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个用于测试的简单项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&amp;ldquo;1.0&amp;rdquo; encoding=&amp;ldquo;UTF-8&amp;rdquo;?&amp;gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;TestMaven&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0-SNAPSHOT&amp;amp;lt;/version&amp;amp;gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class TestUtils {
public static void test() {
System.out.println(&amp;ldquo;家人们谁懂啊，蒸虾头，怎么会有人想吃我家鸽鸽下的蛋&amp;rdquo;);
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;接着我们点击右上角的Maven选项，然后执行&lt;code&gt;install&lt;/code&gt;或直接在命令行中输入&lt;code&gt;mvn install&lt;/code&gt;来安装我们自己的项目到本地Maven仓库中。&lt;/p&gt;&lt;p style=&#34;line-height: 1.6&#34;&gt;接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了，只需要填写和这边一样的坐标：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.test&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;TestMaven&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;接着我们就可以在项目中直接使用了：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
TestUtils.test();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96%EF%BC%88optional%EF%BC%89&#34;&gt;Maven 中的可选依赖（Optional）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Maven 的可选依赖属性 &lt;code&gt;optional&lt;/code&gt; 用于标记某个依赖是否是&lt;strong&gt;可选的&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：Maven 会传递所有依赖的依赖（传递性依赖），即如果项目 A 依赖项目 B，而项目 B 又依赖项目 C，则项目 A 会默认获取 B 和 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;optional&lt;/code&gt; 可以避免这种传递性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当某个依赖是额外的功能模块，而下游项目可能不需要它时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;避免引入无用的依赖，减少构建时间和冲突风险。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，项目 B 依赖项目 C：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;项目 B 中声明 C 为可选依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果：项目 A 不会自动获取 C，除非手动添加。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E4%BE%9D%E8%B5%96%E6%8E%92%E9%99%A4%EF%BC%88exclusions%EF%BC%89&#34;&gt;Maven 中的依赖排除（Exclusions）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;排除传递性依赖中不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;为什么需要？&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;防止依赖冲突（例如不同版本的库）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;删除多余的依赖以优化项目构建。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，而项目 B 又依赖项目 C，但项目 A 不需要 C。&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;传递性依赖的层级示例&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目 A -&amp;gt; 项目 B -&amp;gt; 项目 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果不需要项目 C，可通过 &lt;code&gt;exclusions&lt;/code&gt; 将其排除，最终 A 只包含 B。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;常见问题解决&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖冲突&lt;/strong&gt;：当传递性依赖中某个库的多个版本引入冲突时，排除旧版本并手动引入所需版本。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;避免不必要的依赖&lt;/strong&gt;：减少构建体积，避免不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E7%BB%A7%E6%89%BF%E5%92%8C%E5%A4%9A%E6%A8%A1%E5%9D%97&#34;&gt;&lt;strong&gt;Maven继承和多模块&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89&#34;&gt;&lt;code&gt;2. scope（重点）&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%AD%E3%80%81maven%E5%AE%89%E8%A3%85%E3%80%81%E5%8F%AF%E9%80%89%E5%92%8C%E6%8E%92%E9%99%A4&#34;&gt;&lt;strong&gt;六、Maven安装、可选和排除&lt;/strong&gt;&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E5%AE%89%E8%A3%85&#34;&gt;Maven 安装&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;问题导入：如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢？&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个用于测试的简单项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&amp;ldquo;1.0&amp;rdquo; encoding=&amp;ldquo;UTF-8&amp;rdquo;?&amp;gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;TestMaven&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0-SNAPSHOT&amp;amp;lt;/version&amp;amp;gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class TestUtils {
public static void test() {
System.out.println(&amp;ldquo;家人们谁懂啊，蒸虾头，怎么会有人想吃我家鸽鸽下的蛋&amp;rdquo;);
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;接着我们点击右上角的Maven选项，然后执行&lt;code&gt;install&lt;/code&gt;或直接在命令行中输入&lt;code&gt;mvn install&lt;/code&gt;来安装我们自己的项目到本地Maven仓库中。&lt;/p&gt;&lt;p style=&#34;line-height: 1.6&#34;&gt;接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了，只需要填写和这边一样的坐标：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.test&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;TestMaven&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;接着我们就可以在项目中直接使用了：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
TestUtils.test();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96%EF%BC%88optional%EF%BC%89&#34;&gt;Maven 中的可选依赖（Optional）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Maven 的可选依赖属性 &lt;code&gt;optional&lt;/code&gt; 用于标记某个依赖是否是&lt;strong&gt;可选的&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：Maven 会传递所有依赖的依赖（传递性依赖），即如果项目 A 依赖项目 B，而项目 B 又依赖项目 C，则项目 A 会默认获取 B 和 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;optional&lt;/code&gt; 可以避免这种传递性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当某个依赖是额外的功能模块，而下游项目可能不需要它时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;避免引入无用的依赖，减少构建时间和冲突风险。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，项目 B 依赖项目 C：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;项目 B 中声明 C 为可选依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果：项目 A 不会自动获取 C，除非手动添加。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E4%BE%9D%E8%B5%96%E6%8E%92%E9%99%A4%EF%BC%88exclusions%EF%BC%89&#34;&gt;Maven 中的依赖排除（Exclusions）&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;排除传递性依赖中不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;为什么需要？&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;防止依赖冲突（例如不同版本的库）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;删除多余的依赖以优化项目构建。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，而项目 B 又依赖项目 C，但项目 A 不需要 C。&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;传递性依赖的层级示例&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目 A -&amp;gt; 项目 B -&amp;gt; 项目 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果不需要项目 C，可通过 &lt;code&gt;exclusions&lt;/code&gt; 将其排除，最终 A 只包含 B。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;常见问题解决&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖冲突&lt;/strong&gt;：当传递性依赖中某个库的多个版本引入冲突时，排除旧版本并手动引入所需版本。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;避免不必要的依赖&lt;/strong&gt;：减少构建体积，避免不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope%EF%BC%88%E9%87%8D%E7%82%B9%EF%BC%89&#34;&gt;&lt;code&gt;2. scope（重点）&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%AD%E3%80%81maven%E5%AE%89%E8%A3%85%E3%80%81%E5%8F%AF%E9%80%89%E5%92%8C%E6%8E%92%E9%99%A4&#34;&gt;&lt;strong&gt;六、Maven安装、可选和排除&lt;/strong&gt;&lt;/h1&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E5%AE%89%E8%A3%85&#34;&gt;Maven 安装&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;问题导入：如何在其他项目中引入我们自己编写的Maven项目作为依赖使用呢？&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个用于测试的简单项目：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;?xml version=&amp;ldquo;1.0&amp;rdquo; encoding=&amp;ldquo;UTF-8&amp;rdquo;?&amp;gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;com.test&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;TestMaven&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0-SNAPSHOT&amp;amp;lt;/version&amp;amp;gt;

...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public class TestUtils {
public static void test() {
System.out.println(&amp;ldquo;家人们谁懂啊，蒸虾头，怎么会有人想吃我家鸽鸽下的蛋&amp;rdquo;);
}
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;接着我们点击右上角的Maven选项，然后执行&lt;code&gt;install&lt;/code&gt;或直接在命令行中输入&lt;code&gt;mvn install&lt;/code&gt;来安装我们自己的项目到本地Maven仓库中。&lt;/p&gt;&lt;p style=&#34;line-height: 1.6&#34;&gt;接着我们就可以在需要使用此项目作为依赖的其他项目中使用它了，只需要填写和这边一样的坐标：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;com.test&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;TestMaven&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;接着我们就可以在项目中直接使用了：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
TestUtils.test();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E5%8F%AF%E9%80%89%E4%BE%9D%E8%B5%96%EF%BC%88optional%EF%BC%89&#34;&gt;Maven 中的可选依赖（Optional）&lt;/h3&gt;&lt;h4 style=&#34;&#34; id=&#34;%E4%BD%9C%E7%94%A8&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Maven 的可选依赖属性 &lt;code&gt;optional&lt;/code&gt; 用于标记某个依赖是否是&lt;strong&gt;可选的&lt;/strong&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认行为&lt;/strong&gt;：Maven 会传递所有依赖的依赖（传递性依赖），即如果项目 A 依赖项目 B，而项目 B 又依赖项目 C，则项目 A 会默认获取 B 和 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;使用 &lt;code&gt;optional&lt;/code&gt; 可以避免这种传递性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;%E5%9C%BA%E6%99%AF&#34;&gt;&lt;strong&gt;场景&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;当某个依赖是额外的功能模块，而下游项目可能不需要它时。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;避免引入无用的依赖，减少构建时间和冲突风险。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;%E7%A4%BA%E4%BE%8B&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，项目 B 依赖项目 C：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;项目 B 中声明 C 为可选依赖：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;结果：项目 A 不会自动获取 C，除非手动添加。&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;maven-%E4%B8%AD%E7%9A%84%E4%BE%9D%E8%B5%96%E6%8E%92%E9%99%A4%EF%BC%88exclusions%EF%BC%89&#34;&gt;Maven 中的依赖排除（Exclusions）&lt;/h3&gt;&lt;h4 style=&#34;&#34; id=&#34;%E4%BD%9C%E7%94%A8-1&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;排除传递性依赖中不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;为什么需要？&lt;/strong&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;防止依赖冲突（例如不同版本的库）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;删除多余的依赖以优化项目构建。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h4 style=&#34;&#34; id=&#34;%E7%A4%BA%E4%BE%8B-1&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h4&gt;&lt;p style=&#34;&#34;&gt;项目 A 依赖项目 B，而项目 B 又依赖项目 C，但项目 A 不需要 C。&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-b&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;project-c&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;%E4%BC%A0%E9%80%92%E6%80%A7%E4%BE%9D%E8%B5%96%E7%9A%84%E5%B1%82%E7%BA%A7%E7%A4%BA%E4%BE%8B&#34;&gt;&lt;strong&gt;传递性依赖的层级示例&lt;/strong&gt;&lt;/h4&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;项目 A -&amp;gt; 项目 B -&amp;gt; 项目 C。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果不需要项目 C，可通过 &lt;code&gt;exclusions&lt;/code&gt; 将其排除，最终 A 只包含 B。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;h4 style=&#34;&#34; id=&#34;%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98%E8%A7%A3%E5%86%B3&#34;&gt;&lt;strong&gt;常见问题解决&lt;/strong&gt;&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;依赖冲突&lt;/strong&gt;：当传递性依赖中某个库的多个版本引入冲突时，排除旧版本并手动引入所需版本。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;避免不必要的依赖&lt;/strong&gt;：减少构建体积，避免不需要的模块。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;qiuying&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9B%9B%E3%80%81maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;四、Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BA%94%E3%80%81maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;五、Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope&#34;&gt;&lt;code&gt;2. scope&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
&amp;lt;project xmlns=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&#34;&lt;/a&gt;
xmlns:xsi=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://www.w3.org/2001/XMLSchema-instance%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://www.w3.org/2001/XMLSchema-instance&#34;&lt;/a&gt;
xsi:schemaLocation=&amp;ldquo;&lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/POM/4.0.0&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/POM/4.0.0&lt;/a&gt; &lt;a class=&#34;link&#34; href=&#34;http://maven.apache.org/xsd/maven-4.0.0.xsd%22&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;
    &gt;http://maven.apache.org/xsd/maven-4.0.0.xsd&#34;&lt;/a&gt;&amp;gt;
&amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;lt;groupId&amp;amp;gt;qiuying&amp;amp;lt;/groupId&amp;amp;gt;
&amp;amp;lt;artifactId&amp;amp;gt;BookManage&amp;amp;lt;/artifactId&amp;amp;gt;
&amp;amp;lt;version&amp;amp;gt;1.0&amp;amp;lt;/version&amp;amp;gt;

&amp;amp;lt;properties&amp;amp;gt;
    &amp;amp;lt;maven.compiler.source&amp;amp;gt;17&amp;amp;lt;/maven.compiler.source&amp;amp;gt;
    &amp;amp;lt;maven.compiler.target&amp;amp;gt;17&amp;amp;lt;/maven.compiler.target&amp;amp;gt;
    &amp;amp;lt;project.build.sourceEncoding&amp;amp;gt;UTF-8&amp;amp;lt;/project.build.sourceEncoding&amp;amp;gt;
&amp;amp;lt;/properties&amp;amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;pom%E9%85%8D%E7%BD%AE%E8%A7%A3%E9%87%8A%EF%BC%9A&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;pom配置解释：&lt;/span&gt;&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;project&lt;/mark&gt;:：根节点。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;modelVersion&lt;/mark&gt;:：定义了当前模型的版本，不用管它。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;groupId、artifactId、version&lt;/mark&gt;:：这三个元素合在一起，用于唯一区别每个项目，别人如果需要将我们编写的代码作为依赖，那么就必须通过这三个元素来定位我们的项目，我们称为一个项目的基本坐标，所有的项目一般都有自己的Maven坐标，因此我们通过Maven导入其他的依赖只需要填写这三个基本元素就可以了，无需再下载Jar文件，而是Maven自动帮助我们下载依赖并导入。&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;groupId&lt;/code&gt; 一般用于指定组名称，命名规则一般和包名一致，比如我们这里使用的是&lt;code&gt;org.example&lt;/code&gt;，一个组下面可以有很多个项目。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;artifactId&lt;/code&gt; 一般用于指定项目在当前组中的唯一名称，也就是说在组中用于区分于其他项目的标记。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;version&lt;/code&gt; 代表项目版本，随着我们项目的开发和改进，版本号也会不断更新，我们可以手动指定当前项目的版本号，其他人使用我们的项目作为依赖时，也可以根据版本号进行选择（这里的SNAPSHOT代表快照，一般表示这是一个处于开发中的项目，正式发布项目一般只带版本号）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;mark data-color=&#34;#fef9c3&#34; style=&#34;background-color: #fef9c3; color: inherit&#34;&gt;properties&lt;/mark&gt;：这里一般都是一些变量和选项的配置，我们这里指定了JDK的源代码和编译版本为17，同时下面的源代码编码格式为UTF-8，无需进行修改。&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E4%BE%9D%E8%B5%96%E5%AF%BC%E5%85%A5&#34;&gt;Maven依赖导入&lt;/h1&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependencies&amp;gt;
//里面填写的就是所有的依赖
&amp;lt;/dependencies&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;举例说明（以插入Lombok依赖为例）：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.18.36&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h1 style=&#34;&#34; id=&#34;maven%E4%BE%9D%E8%B5%96%E4%BD%9C%E7%94%A8%E5%9F%9F&#34;&gt;Maven依赖作用域&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;除了三个基本的属性用于定位坐标外，依赖还可以添加以下属性：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;type&lt;/strong&gt;：依赖的类型，对于项目坐标定义的packaging。大部分情况下，该元素不必声明，其默认值为jar&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;scope&lt;/strong&gt;：依赖的范围&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;optional&lt;/strong&gt;：标记依赖是否可选&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;exclusions&lt;/strong&gt;：用来排除传递性依赖（一个项目有可能依赖于其他项目，就像我们的项目，如果别人要用我们的项目作为依赖，那么就需要一起下载我们项目的依赖，如Lombok）&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;1.-type&#34;&gt;&lt;code&gt;1. type&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的类型，对应项目的打包类型（&lt;code&gt;packaging&lt;/code&gt;）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;jar&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的类型不是 &lt;code&gt;jar&lt;/code&gt; 时，例如 &lt;code&gt;war&lt;/code&gt;（Web 应用）、&lt;code&gt;pom&lt;/code&gt;（父项目定义）、&lt;code&gt;zip&lt;/code&gt; 等，需要显式声明。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;example-artifact&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;type&amp;gt;war&amp;lt;/type&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h3 style=&#34;&#34; id=&#34;2.-scope&#34;&gt;&lt;code&gt;2. scope&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：定义依赖的作用范围。主要范围包括：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;compile&lt;/code&gt;（默认值）：编译、测试和运行时都需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;provided&lt;/code&gt;：编译和测试时需要，但运行时由容器（如 Tomcat）提供。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;runtime&lt;/code&gt;：运行和测试时需要，编译时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;test&lt;/code&gt;：仅测试时需要，编译和运行时不需要。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;system&lt;/code&gt;：类似于 &lt;code&gt;provided&lt;/code&gt;，但需要本地提供依赖路径（几乎不用）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;code&gt;import&lt;/code&gt;：用于引入 BOM（Bill of Materials）依赖管理。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;3.-optional&#34;&gt;3. &lt;code&gt;optional&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：标记依赖是否为可选依赖，避免被传递到依赖的消费者（下游项目）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;默认值&lt;/strong&gt;：&lt;code&gt;false&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖是可选功能模块，不想影响下游项目时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.example&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;optional-lib&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;1.0.0&amp;lt;/version&amp;gt;
&amp;lt;optional&amp;gt;true&amp;lt;/optional&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;4.-exclusions&#34;&gt;4. &lt;code&gt;exclusions&lt;/code&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;作用&lt;/strong&gt;：用于排除传递性依赖，防止不必要的依赖被引入。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;使用场景&lt;/strong&gt;：当依赖的项目中包含的某些传递性依赖与你的项目冲突时。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-xml&#34;&gt;&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-web&amp;lt;/artifactId&amp;gt;
&amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
&amp;lt;exclusions&amp;gt;
&amp;lt;exclusion&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-tomcat&amp;lt;/artifactId&amp;gt;
&amp;lt;/exclusion&amp;gt;
&amp;lt;/exclusions&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Lambda表达式</title>
        <link>https://qiuyingtyan.top/p/lambda/</link>
        <pubDate>Fri, 22 Nov 2024 15:59:00 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/lambda/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/97622912_p0_master1200.webp" alt="Featured image of post Lambda表达式" /&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BB%80%E4%B9%88%E6%98%AFlambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%9F&#34;&gt;&lt;strong&gt;什么是Lambda表达式？&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;Lambda 表达式是 Java 中的一种简洁语法，用于表示&lt;strong&gt;匿名函数&lt;/strong&gt;。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;它是 Java 8 中引入的功能，旨在提高代码的&lt;strong&gt;简洁性&lt;/strong&gt;和&lt;strong&gt;可读性&lt;/strong&gt;。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;尤其是在处理&lt;strong&gt;函数式编程&lt;/strong&gt;或需要传递行为的场景下，例如集合操作、并行流处理等。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E6%88%91%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E5%AD%A6%E4%B9%A0%E6%88%96%E4%BD%BF%E7%94%A8lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%9F&#34;&gt;我们为什么要学习或使用Lambda表达式？&lt;/h1&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;代码更简洁&lt;/strong&gt;：减少了匿名类的样板代码。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;更具可读性&lt;/strong&gt;：将行为直接传递给函数。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;结合 Stream API&lt;/strong&gt; 提高数据处理的效率和易读性。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E4%BB%80%E4%B9%88%E6%97%B6%E5%80%99%E5%8F%AF%E4%BB%A5%E7%94%A8lambda%E8%A1%A8%E8%BE%BE%E5%BC%8F%EF%BC%9F&#34;&gt;什么时候可以用Lambda表达式？&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;如果一个接口中有且只有一个待实现的抽象方法，&lt;/strong&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;那么我们可以将匿名内部类简写为Lambda表达式&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;public static void main(String[] args) {
    Study study = () -&amp;gt; System.out.println(&#34;我是逆蝶！&#34;);
  	study.study();
}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9&#34;&gt;&lt;strong&gt;注意事项&lt;/strong&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Lambda 表达式只能用于&lt;strong&gt;函数式接口&lt;/strong&gt;（接口中有且只有一个抽象方法）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;如果需要使用外部变量，它必须是&lt;strong&gt;隐式 final&lt;/strong&gt;（不能在 Lambda 表达式内外修改其值）。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E7%9A%84%E8%AF%AD%E6%B3%95&#34;&gt;Lambda 表达式的语法&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;基本语法结构为：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;(参数列表) -&amp;gt; {方法体}&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E6%9E%84%E6%88%90%E9%83%A8%E5%88%86&#34;&gt;&lt;strong&gt;构成部分&lt;/strong&gt;&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;参数列表&lt;/strong&gt;：可以有零个、一个或多个参数，参数类型可以省略（由编译器推断）。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;箭头符号 (&lt;/strong&gt;&lt;code&gt;-&amp;gt;&lt;/code&gt;&lt;strong&gt;)&lt;/strong&gt;：分隔参数列表和方法体。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;方法体&lt;/strong&gt;：包含 Lambda 表达式的逻辑，可用一条或多条语句。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;或者可以这么表示：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;([参数类型 参数名称,]...) ‐&amp;gt; { 代码语句，包括返回值 }&lt;/code&gt;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;和匿名内部类不同，Lambda仅支持接口，不支持抽象类&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;接口内部必须有且仅有一个抽象方法（可以有多个方法，但是必须保证其他方法有默认实现，必须留一个抽象方法出来）&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E7%A4%BA%E4%BE%8B&#34;&gt;&lt;strong&gt;示例&lt;/strong&gt;&lt;/h3&gt;&lt;h4 style=&#34;&#34; id=&#34;1.-%E6%97%A0%E5%8F%82%E6%95%B0%E7%9A%84-lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F&#34;&gt;1. 无参数的 Lambda 表达式&lt;/h4&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;() -&amp;gt; System.out.println(&#34;Hello Lambda!&#34;);&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;2.-%E6%9C%89%E4%B8%80%E4%B8%AA%E5%8F%82%E6%95%B0%E7%9A%84-lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F&#34;&gt;2. 有一个参数的 Lambda 表达式&lt;/h4&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;x -&amp;gt; System.out.println(x);&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;3.-%E6%9C%89%E5%A4%9A%E4%B8%AA%E5%8F%82%E6%95%B0%E7%9A%84-lambda-%E8%A1%A8%E8%BE%BE%E5%BC%8F&#34;&gt;3. 有多个参数的 Lambda 表达式&lt;/h4&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;(a, b) -&amp;gt; a + b&lt;/code&gt;&lt;/pre&gt;&lt;h4 style=&#34;&#34; id=&#34;4.-%E6%9C%89%E5%A4%9A%E6%9D%A1%E8%AF%AD%E5%8F%A5%E7%9A%84%E6%96%B9%E6%B3%95%E4%BD%93&#34;&gt;4. 有多条语句的方法体&lt;/h4&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;(x, y) -&amp;gt; { int sum = x + y; return sum; }&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;没看懂？那让我们举一个不那么抽象的例子：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;@FunctionalInterface   //添加了此注解的接口，都支持lambda表达式，符合函数式接口定义
public interface Runnable {
    public abstract void run();   //有且仅有一个抽象方法，此方法返回值为void，且没有参数
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;因此，Runable的的匿名内部类实现，就可以简写为：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;Runnable runnable = () -&amp;gt; {    };&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;我们也可以写一个玩玩：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;@FunctionalInterface
public interface Test {   //接口类型
    String test(Integer i);    //只有这一个抽象方法，且接受一个int类型参数，返回一个String类型结果
}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;span style=&#34;font-size: 15.98px; color: rgb(93, 93, 93)&#34;&gt;它的Lambda表达式的实现就可以写为：&lt;/span&gt;&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Java&#34;&gt;Test test = (Integer i) -&amp;gt; { return i+&#34;&#34;; };  //这里我们就简单将i转换为字符串形式&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>一些回忆——搭建该博客的流程</title>
        <link>https://qiuyingtyan.top/p/memory_blog/</link>
        <pubDate>Wed, 13 Nov 2024 06:41:06 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/memory_blog/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/88278917_p0_master1200.webp" alt="Featured image of post 一些回忆——搭建该博客的流程" /&gt;&lt;h1 style=&#34;&#34; id=&#34;%E6%B3%A8%E5%86%8C%E5%9F%9F%E5%90%8D&#34;&gt;注册域名&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;什么是域名？&lt;/p&gt;&lt;p style=&#34;&#34;&gt;域名可以通俗地理解为互联网上的“门牌号码”或“地址”。每个网站在互联网上都有一个唯一的地址，这个地址就是域名。比如，人们常常访问的“baidu.com”，“taobao.com”等都是域名。它们由一串字符组成，通常包括字母、数字和连接符“-”，并由“.”分隔成几部分。域名的作用是让人们能够更容易地访问和记住网站，而不需要记住复杂的IP地址。同时，域名也具有一定的商业价值，可以作为企业或个人在互联网上的标识和品牌形象。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;域名注册&lt;/p&gt;&lt;p style=&#34;&#34;&gt;博主域名是在阿里云购买的&lt;/p&gt;&lt;p style=&#34;&#34;&gt;官网：阿里云&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://www.aliyun.com/&#34;&gt;阿里云-计算，为了无法计算的价值&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;首先注册账户，然后输入你想购买的域名&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E6%B3%A8%E5%86%8C%E5%9F%9F%E5%90%8D.webp&#34; alt=&#34;注册域名.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%9F%9F%E5%90%8D%E5%A4%87%E6%A1%88&#34;&gt;域名备案&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;然后到域名控制台进行&lt;strong&gt;实名认证&lt;/strong&gt;和&lt;strong&gt;解析域名&lt;/strong&gt;就行。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;如果你用的内地服务器那还需要进行域名备案。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;备案的流程就不细说，自己去了解一下就行。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E8%A7%A3%E6%9E%90%E5%9F%9F%E5%90%8D%26%E5%AE%9E%E5%90%8D%E8%AE%A4%E8%AF%81.webp&#34; alt=&#34;解析域名&amp;amp;实名认证.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E8%B4%AD%E4%B9%B0%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8&#34;&gt;购买云服务器&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;准备&lt;/p&gt;&lt;p style=&#34;&#34;&gt;首先需要一台云服务器，要有&lt;strong&gt;公网IP&lt;/strong&gt;的，推荐雨云的：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;雨云优惠注册地址&lt;/strong&gt;：&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;https://www.rainyun.com/114514aa_&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;优惠码：114514aa&lt;/p&gt;&lt;p style=&#34;&#34;&gt;使用优惠码注册后绑定微信可获得5折优惠券&lt;/p&gt;&lt;p style=&#34;&#34;&gt;注册完账号后进到雨云控制台，云服务器入口可以在后台的 总览 和 云产品 部分找到：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E9%9B%A8%E4%BA%91%E6%8E%A7%E5%88%B6%E5%8F%B0.webp&#34; alt=&#34;雨云控制台.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;点击购买云服务器，接着选择服务器区域，国内用户建议选择内地机房，因为延迟低网络稳定，比如宿迁和十堰，其中推荐十堰，因为IP便宜，如果预算充足选择宿迁更好（防御高，BGP线路）。但如果你没有备案域名那建议选择香港或美国的服务器。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;这里我买了HK的服务器（因为懒得备案）&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E8%B4%AD%E4%B9%B0%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8(HK).webp&#34; alt=&#34;购买云服务器(HK).png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;配置选择&lt;strong&gt;2核2G&lt;/strong&gt;一般够用了，如果你网站用户多就选高点的配置，也可以后期升级配置。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%B4%AD%E4%B9%B0%E9%85%8D%E7%BD%AE.webp&#34; alt=&#34;云服务器购买配置.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;系统选&lt;strong&gt;Debian11&lt;/strong&gt;就行，预安装APP一个都别选（因为可能会有些不太好的事情发生，别问，问就说是发生了些不友好的经历...）&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E9%A2%84%E5%AE%89%E8%A3%85%E7%B3%BB%E7%BB%9F.webp&#34; alt=&#34;预安装系统.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;都选好后就可以点击立即购买了，也可以选择1元试用1天。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;购买后即可在我的云服务器这里看到你买的云服务器，点击管理。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E8%B4%AD%E4%B9%B0%E5%AE%8C%E6%AF%95%EF%BC%8C%E7%82%B9%E5%87%BB%E7%AE%A1%E7%90%86.webp&#34; alt=&#34;购买完毕，点击管理.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%851panel%E9%9D%A2%E6%9D%BF&#34;&gt;安装1Panel面板&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;首先需要通过&lt;strong&gt;SSH客户端连接服务器&lt;/strong&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;下载安装并打开ssh客户端软件，ssh客户端软件推荐putty或mobaxterm，还有用win自带的终端或CMD也行&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/SSH%E8%BF%9E%E6%8E%A5.webp&#34; alt=&#34;SSH连接.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;安装1Panel&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh &amp;amp;&amp;amp; bash quick_start.sh&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;安装成功后，控制台会打印面板访问信息，可通过浏览器访问 1Panel：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;http://目标服务器 IP 地址:目标端口/安全入口&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;如果使用的是云服务器，请至安全组开放目标端口。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;ssh 登录 1Panel 服务器后，执行 1pctl user-info 命令可获取安全入口（entrance）&lt;/p&gt;&lt;p style=&#34;&#34;&gt;安装成功后，可使用 1pctl 命令行工具来维护 1Panel&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;span fontsize=&#34;&#34; color=&#34;&#34;&gt;记得&lt;strong&gt;记住账号密码&lt;/strong&gt;噢&lt;/span&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;然后浏览器输入地址登录进去就行惹&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/1Panel%E9%9D%A2%E6%9D%BF.webp&#34; alt=&#34;1Panel面板.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;接着安装应用&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel&#34;&gt;使用 1Panel 部署 | Halo 文档&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;1Panel 简介&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel#1panel-%E7%AE%80%E4%BB%8B&#34; class=&#34;hash-link&#34;&gt;​&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;a rel=&#34;noopener noreferrer&#34; href=&#34;https://1panel.cn/&#34; target=&#34;_blank&#34;&gt;1Panel&lt;/a&gt; 是一个现代化、开源的 Linux 服务器运维管理面板。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/1panel-6ffbe25fad8e4cf600af312928911090.png&#34; alt=&#34;1Panel 截图&#34; width=&#34;3840&#34; height=&#34;2975&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;功能&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel#%E5%8A%9F%E8%83%BD&#34; class=&#34;hash-link&#34;&gt;​&lt;/a&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;快速建站&lt;/strong&gt;：深度集成 WordPress 和 Halo，域名绑定、SSL 证书配置等一键搞定。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;高效管理&lt;/strong&gt;：通过 Web 端轻松管理 Linux 服务器，包括应用管理、主机监控、文件管理、数据库管理、容器管理等。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;安全可靠&lt;/strong&gt;：最小漏洞暴露面，提供防火墙和安全审计等功能。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;一键备份&lt;/strong&gt;：支持一键备份和恢复，备份数据云端存储，永不丢失。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;安装基础软件&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel#%E5%AE%89%E8%A3%85%E5%9F%BA%E7%A1%80%E8%BD%AF%E4%BB%B6&#34; class=&#34;hash-link&#34;&gt;​&lt;/a&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;在安装 Halo 之前，我们需要先在 1Panel 上安装好所需的软件，包括 OpenResty 和数据库（MySQL、PostgreSQL、MariaDB 都可以）。在接下来的文档中，我们会默认你已经安装好了这两个软件，并不再赘述。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/openresty-mysql-56dfce15a5de885bca88391d36789080.png&#34; alt=&#34;OpenResty 和 MySQL&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%85-halo-%E5%BA%94%E7%94%A8%E2%80%8B&#34;&gt;安装 Halo 应用&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel#%E5%AE%89%E8%A3%85-halo-%E5%BA%94%E7%94%A8&#34; class=&#34;hash-link&#34;&gt;​&lt;/a&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;进入应用商店应用列表，选择其中的 Halo 应用进行安装。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/app-store-halo-acd5c156658ced46a4538cf6ac12c4b0.png&#34; alt=&#34;选择 Halo 应用&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;在应用详情页选择最新的 Halo 版本进行安装。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/install-halo-6ede4c3cb9e35901443411387b3b84ae.png&#34; alt=&#34;选择 Halo 版本&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;参数说明：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;名称&lt;/strong&gt;：要创建的 Halo 应用的名称。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;版本&lt;/strong&gt;：选择最新的版本即可。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;数据库服务&lt;/strong&gt;：Halo 应用使用的数据库应用，支持下拉选择已安装的数据库应用，1Panel 会自动配置 Halo 使用该数据库。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;数据库名&lt;/strong&gt;：Halo 应用使用的数据库名称，1Panel 会在选中的数据库中自动创建这个数据库。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;数据库用户&lt;/strong&gt;：Halo 应用使用的数据库用户名，1Panel 会在选中的数据库中自动创建这个用户，并添加对应的数据库授权。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;数据库用户密码&lt;/strong&gt;：Halo 应用使用的数据库用户密码，1Panel 会在选中的数据库中自动为上一步创建的用户配置该密码。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;外部访问地址&lt;/strong&gt;：Halo 应用的最终访问地址，如果有为 Halo 规划域名，需要配置为域名格式，例如 &lt;code&gt;http://halo.example.com&lt;/code&gt;。否则配置为 &lt;code&gt;http://服务器IP:PORT&lt;/code&gt;，例如 &lt;code&gt;http://192.168.1.1:8090&lt;/code&gt;。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;&lt;strong&gt;端口&lt;/strong&gt;：Halo 应用的服务端口。&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;开始安装后页面自动跳转到已安装应用列表，等待刚刚安装的 Halo 应用变为已启动状态。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/halo-status-508f621ea03c74f52806c1ee5aded93f.png&#34; alt=&#34;Halo 运行状态&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%88%9B%E5%BB%BA%E7%BD%91%E7%AB%99%E2%80%8B&#34;&gt;创建网站&lt;a href=&#34;https://docs.halo.run/getting-started/install/1panel#%E5%88%9B%E5%BB%BA%E7%BD%91%E7%AB%99&#34; class=&#34;hash-link&#34;&gt;​&lt;/a&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;完成 Halo 应用的安装后，此时并不会自动创建一个网站，我们需要手动创建一个网站，然后将 Halo 应用绑定到这个网站上才能使用域名访问。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;点击 1Panel 菜单的 &lt;strong&gt;网站&lt;/strong&gt;，进入网站列表页，点击 &lt;strong&gt;创建网站&lt;/strong&gt; 按钮。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/new-site-c1a818150254182834e6c74074d6ccb6.png&#34; alt=&#34;创建网站&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;在已装应用中选择我们刚刚新建的 Halo 应用。&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;正确填写主域名，需要注意的是需要提前解析好域名到服务器 IP。&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p style=&#34;&#34;&gt;最后，点击确认按钮，等待网站创建完成即可访问网站进行 &lt;a href=&#34;https://docs.halo.run/getting-started/setup&#34;&gt;初始化&lt;/a&gt;。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://docs.halo.run/assets/images/site-5005ab086c0fb2b1d83319f951e05a5b.png&#34; alt=&#34;网站列表&#34; width=&#34;2988&#34; height=&#34;1532&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;这样我们就部署完成了&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>关于如何在CentOS8上部署若依项目的思考</title>
        <link>https://qiuyingtyan.top/p/ruoyi_bushu/</link>
        <pubDate>Wed, 13 Nov 2024 00:54:13 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/p/ruoyi_bushu/</guid>
        <description>&lt;img src="https://qiuyingtyan.top/upload/87762152_p0_master1200.webp" alt="Featured image of post 关于如何在CentOS8上部署若依项目的思考" /&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%89%8D%E6%8F%90%E6%9D%A1%E4%BB%B6&#34;&gt;&lt;strong&gt;前提条件&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Java环境：确保安装了jdk(博主用的jdk11.0.23)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;数据库：MySQL(博主用的MySQL8.0.26)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Redis：在若依项目中通常用作缓存和消息队列，提升数据访问速度和处理能力(博主用的redis0.5.3)&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p style=&#34;&#34;&gt;Nginx：作为反向代理服务器，可以处理请求负载均衡、静态资源服务和 HTTPS 加密，确保高效的流量管理和更好的性能。两者结合使用，可以极大提升应用的响应速度和可靠性(博主用的nginx1.14.1)&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E5%85%B7%E4%BD%93%E6%93%8D%E4%BD%9C&#34;&gt;&lt;strong&gt;具体操作&lt;/strong&gt;&lt;/h1&gt;&lt;h2 style=&#34;&#34; id=&#34;java&#34;&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/h2&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%85jdk&#34;&gt;安装jdk&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;第一种方法：个人建议去官网上下载jdk的jar包&lt;/p&gt;&lt;p style=&#34;&#34;&gt;访问官方网站：前往 Oracle JDK 下载页面 或 OpenJDK 下载页面。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;选择版本：选择你需要的JDK版本（记得选Linux x64哦）。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;下载包：找到对应的JAR包或安装包（通常是.tar.gz或.zip格式），点击下载。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;解压缩（如需要）：下载完成后，如果是压缩包，可以使用以下命令解压：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;tar -zxvf jdk-&amp;lt;version&amp;gt;.tar.gz&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;把下载好的jar包直接拖进你的home文件夹里&lt;/p&gt;&lt;p style=&#34;&#34;&gt;第二种方法：直接通过命令行下载&lt;/p&gt;&lt;p style=&#34;&#34;&gt;通过包管理器安装&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo dnf install java-11-openjdk-devel&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;确认安装：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;java -version&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h2 style=&#34;&#34; id=&#34;mysql&#34;&gt;&lt;strong&gt;MySQL&lt;/strong&gt;&lt;/h2&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%85mysql&#34;&gt;安装MySQL&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo dnf install @mysql&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%90%AF%E5%8A%A8mysql%E6%9C%8D%E5%8A%A1&#34;&gt;启动MySQL服务&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl start mysqld&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E8%AE%BE%E7%BD%AEmysql%E6%9C%8D%E5%8A%A1&#34;&gt;设置MySQL服务&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl enable mysqld&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E8%BF%90%E8%A1%8C%E5%AE%89%E5%85%A8%E9%85%8D%E7%BD%AE&#34;&gt;运行安全配置&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo mysql_secure_installation&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E7%99%BB%E5%BD%95mysql%E5%B9%B6%E5%88%9B%E5%BB%BA%E8%8B%A5%E4%BE%9D%E9%A1%B9%E7%9B%AE%E9%9C%80%E8%A6%81%E7%9A%84%E6%95%B0%E6%8D%AE%E5%BA%93%E5%92%8C%E7%94%A8%E6%88%B7&#34;&gt;登录MySQL并创建若依项目需要的数据库和用户&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;mysql -u root -p&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BF%AE%E6%94%B9-root-%E7%9A%84%E5%AF%86%E7%A0%81%E4%B8%BA-123456&#34;&gt;修改 root 的密码为 123456&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;ALTER USER &#39;root&#39;@&#39;localhost&#39; IDENTIFIED WITH mysql_native_password BY &#39;123456&#39;;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BF%AE%E6%94%B9-root-%E5%8F%AF%E4%BB%A5%E8%BF%9C%E7%A8%8B%E7%99%BB%E5%BD%95&#34;&gt;修改 root 可以远程登录&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;update user set host = &#39;%&#39; where user = &#39;root&#39;;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%9C%A8mysql%E6%8F%90%E7%A4%BA%E7%AC%A6%E4%B8%8B%E6%89%A7%E8%A1%8C&#34;&gt;在MySQL提示符下执行&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;CREATE DATABASE ruoyi;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;CREATE USER &#39;ruoyiuser&#39;@&#39;localhost&#39; IDENTIFIED BY &#39;your_password&#39;;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;GRANT ALL PRIVILEGES ON ruoyi.* TO &#39;ruoyiuser&#39;@&#39;localhost&#39;;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;FLUSH PRIVILEGES;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-MySQL&#34;&gt;EXIT;&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BF%AE%E6%94%B9-mysql-%E7%9A%84%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6&#34;&gt;修改 mysql 的配置文件&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BF%AE%E6%94%B9%E5%A6%82%E4%B8%8B%E9%85%8D%E7%BD%AE&#34;&gt;修改如下配置&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;bind-address=0.0.0.0&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E9%87%8D%E5%90%AF-mysql-%E6%9C%8D%E5%8A%A1&#34;&gt;重启 mysql 服务&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;service mysql restart&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E4%BD%BF%E7%94%A8%E5%A6%82%E4%B8%8B%E5%91%BD%E4%BB%A4%E6%9F%A5%E7%9C%8B-mysql-%E6%9C%8D%E5%8A%A1%E7%8A%B6%E6%80%81&#34;&gt;使用如下命令查看 MySQL 服务状态&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;service mysql status&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h2 style=&#34;&#34; id=&#34;redis&#34;&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/h2&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%85-redis&#34;&gt;安装 Redis&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo dnf install epel-release -y&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo dnf install redis -y&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%90%AF%E5%8A%A8-redis&#34;&gt;启动 Redis&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl start redis&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E8%AE%BE%E7%BD%AE-redis&#34;&gt;设置 Redis&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl enable redis&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E9%AA%8C%E8%AF%81-redis-%E6%98%AF%E5%90%A6%E6%AD%A3%E5%B8%B8%E8%BF%90%E8%A1%8C%EF%BC%9A&#34;&gt;验证 Redis 是否正常运行：&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;redis-cli ping&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;返回 PONG 就是正常运行啦！&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h2 style=&#34;&#34; id=&#34;nginx&#34;&gt;&lt;strong&gt;Nginx&lt;/strong&gt;&lt;/h2&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%AE%89%E8%A3%85-nginx&#34;&gt;安装 Nginx&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo dnf install nginx -y&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%90%AF%E5%8A%A8-nginx&#34;&gt;启动 Nginx&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl start nginx&lt;/code&gt;&lt;/pre&gt;&lt;h3 style=&#34;&#34; id=&#34;%E8%AE%BE%E7%BD%AE-nginx&#34;&gt;设置 Nginx&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo systemctl enable nginx&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;h1 style=&#34;&#34; id=&#34;%E9%83%A8%E7%BD%B2%E8%8B%A5%E4%BE%9D%E9%A1%B9%E7%9B%AE&#34;&gt;&lt;strong&gt;部署若依项目&lt;/strong&gt;&lt;/h1&gt;&lt;p style=&#34;&#34;&gt;ps：博主自己从阿里的源下载失败了，所以这里就推荐用jar包&lt;/p&gt;&lt;p style=&#34;&#34;&gt;具体步骤：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;进入若依的官网，然后复制箭头所指的地址&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E8%8B%A5%E4%BE%9D%E5%AE%98%E7%BD%91.webp&#34; alt=&#34;若依官网.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;打开你的IDEA，&#34;File&#34;→&#34;Close Project&#34;，关闭现有的项目&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&amp;nbsp;然后新建&#34;Project&#34;→&#34;Get from VCS&#34;→在&#34;URL那行粘贴下载地址&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/IDEA001.webp&#34; alt=&#34;IDEA001.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/IDEA002.webp&#34; alt=&#34;IDEA002.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE%E5%90%8E%EF%BC%8C%E6%9B%B4%E6%94%B9%E4%B8%BB%E5%BA%93%E6%95%B0%E6%8D%AE%E6%BA%90&#34;&gt;创建项目后，更改主库数据源&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E6%9B%B4%E6%94%B9%E4%B8%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E6%BA%90.webp&#34; alt=&#34;更改主数据库源.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A1%A8&#34;&gt;准备数据库表&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE%E5%BA%9301.webp&#34; alt=&#34;准备数据库01.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE%E5%BA%9302.webp&#34; alt=&#34;准备数据库02.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;先创建一个数据库，这里我们创建一个名为 ruoyi 的数据库。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;将项目所需的表创建。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;依次将两个 sql 文件中的内容拷贝到 navicat 中，在 sql 中添加使用当前数据库的语句：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;然后执行整个 sql。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;两个 sql 文件全部执行之后，会生成这些表：&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE%E5%BA%9303.webp&#34; alt=&#34;准备数据库03.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E9%85%8D%E7%BD%AE%E6%95%B0%E6%8D%AE%E5%BA%93&#34;&gt;配置数据库&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;编辑 application-dev.yml 或 application.yml，配置数据库连接：&lt;/p&gt;&lt;pre&gt;&lt;code&gt;spring:
      datasource:
        url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&amp;amp;characterEncoding=utf8&amp;amp;serverTimezone=UTC
        username: ruoyiuser
        password: your_password&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;先运行一遍确保没有报错，然后打开右侧的&#34;maven&#34;→&#34;ruoyi&#34;→&#34;Lifecycle&#34;→&#34;package&#34;，然后等待打包完成，就可以在左侧的&#34;ruoyi-admin&#34;→&#34;target&#34; 看到&#34;ruoyi-admin.jar&#34;了。&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E6%89%93%E5%8C%85%E8%8B%A5%E4%BE%9D.webp&#34; alt=&#34;打包若依.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;然后右键&#34;ruoyi-admin.jar&#34;→&#34;Open in&#34;→&#34;Explorer&#34;,你就看到若依的jar包啦&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E6%96%B0%E5%BB%BA%E9%83%A8%E7%BD%B2%E7%9B%AE%E5%BD%95&#34;&gt;新建部署目录&lt;/h3&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;mkdir -p /opt/deploy/ruoyi/{api,web}&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;把你的若依jar包放进api里&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E5%90%AF%E5%8A%A8%E8%8B%A5%E4%BE%9D%E9%A1%B9%E7%9B%AE&#34;&gt;启动若依项目&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;在 target 目录下运行：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;java -jar ruoyi-admin.jar&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;此时后端已经准备完毕，我们接下来准备前端&lt;/p&gt;&lt;p style=&#34;&#34;&gt;将ruoyi-vue里的ruoyi-ui打开，然后&lt;/p&gt;&lt;p style=&#34;&#34;&gt;1、安装依赖包，运行 RUOYI-VUE/bin/package.bat&lt;/p&gt;&lt;p style=&#34;&#34;&gt;2、打包构建，运行 RUOYI-VUE/bin/build.bat&lt;/p&gt;&lt;p style=&#34;&#34;&gt;（前提：已安装nodejs和yarn）&lt;/p&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF01.webp&#34; alt=&#34;部署前端01.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;p style=&#34;&#34;&gt;然后把这web文件放这里边&lt;/p&gt;&lt;pre&gt;&lt;code&gt;/opt/deploy/ruoyi/web&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;&lt;img src=&#34;https://qiuyingtyan.top/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF02.webp&#34; alt=&#34;部署前端02.png&#34; width=&#34;100%&#34; height=&#34;100%&#34; style=&#34;display: inline-block&#34;&gt;&lt;/p&gt;&lt;h3 style=&#34;&#34; id=&#34;%E9%85%8D%E7%BD%AEnginx&#34;&gt;配置Nginx&lt;/h3&gt;&lt;p style=&#34;&#34;&gt;创建新的配置文件：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;sudo vi /etc/nginx/conf.d/ruoyi.conf&lt;/code&gt;&lt;/pre&gt;&lt;p style=&#34;&#34;&gt;添加以下内容：&lt;/p&gt;&lt;pre&gt;&lt;code class=&#34;language-Shell&#34;&gt;server {
        listen 80;
        server_name your_domain_or_ip;
&lt;pre&gt;&lt;code&gt;    location / {
        proxy_pass http://localhost:8080;  # 若依默认端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后Esc → ： → wq&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E9%87%8D%E5%90%AF-nginx&amp;quot;&amp;gt;重启 Nginx&amp;lt;/h3&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;sudo systemctl restart nginx&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C&amp;quot;&amp;gt;最终效果&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;最后，打开浏览器，访问 http://your_domain_or_ip，就可以看到若依的登录界面了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%89%8D%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;前端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%90%8E%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;后端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
  datasource:
    url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&amp;amp;amp;characterEncoding=utf8&amp;amp;amp;serverTimezone=UTC
    username: ruoyiuser
    password: your_password&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;先运行一遍确保没有报错，然后打开右侧的&amp;quot;maven&amp;quot;→&amp;quot;ruoyi&amp;quot;→&amp;quot;Lifecycle&amp;quot;→&amp;quot;package&amp;quot;，然后等待打包完成，就可以在左侧的&amp;quot;ruoyi-admin&amp;quot;→&amp;quot;target&amp;quot; 看到&amp;quot;ruoyi-admin.jar&amp;quot;了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E6%89%93%E5%8C%85%E8%8B%A5%E4%BE%9D.webp&amp;quot; alt=&amp;quot;打包若依.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后右键&amp;quot;ruoyi-admin.jar&amp;quot;→&amp;quot;Open in&amp;quot;→&amp;quot;Explorer&amp;quot;,你就看到若依的jar包啦&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E6%96%B0%E5%BB%BA%E9%83%A8%E7%BD%B2%E7%9B%AE%E5%BD%95&amp;quot;&amp;gt;新建部署目录&amp;lt;/h3&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;mkdir -p /opt/deploy/ruoyi/{api,web}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;把你的若依jar包放进api里&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E5%90%AF%E5%8A%A8%E8%8B%A5%E4%BE%9D%E9%A1%B9%E7%9B%AE&amp;quot;&amp;gt;启动若依项目&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;在 target 目录下运行：&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;java -jar ruoyi-admin.jar&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;此时后端已经准备完毕，我们接下来准备前端&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;将ruoyi-vue里的ruoyi-ui打开，然后&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;1、安装依赖包，运行 RUOYI-VUE/bin/package.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;2、打包构建，运行 RUOYI-VUE/bin/build.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;（前提：已安装nodejs和yarn）&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF01.webp&amp;quot; alt=&amp;quot;部署前端01.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后把这web文件放这里边&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;/opt/deploy/ruoyi/web&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF02.webp&amp;quot; alt=&amp;quot;部署前端02.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E9%85%8D%E7%BD%AEnginx&amp;quot;&amp;gt;配置Nginx&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;创建新的配置文件：&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;sudo vi /etc/nginx/conf.d/ruoyi.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;添加以下内容：&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;server {
    listen 80;
    server_name your_domain_or_ip;

    location / {
        proxy_pass http://localhost:8080;  # 若依默认端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后Esc → ： → wq&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E9%87%8D%E5%90%AF-nginx&amp;quot;&amp;gt;重启 Nginx&amp;lt;/h3&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;sudo systemctl restart nginx&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C&amp;quot;&amp;gt;最终效果&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;最后，打开浏览器，访问 http://your_domain_or_ip，就可以看到若依的登录界面了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%89%8D%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;前端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%90%8E%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;后端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
  datasource:
    url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&amp;amp;amp;characterEncoding=utf8&amp;amp;amp;serverTimezone=UTC
    username: ruoyiuser
    password: your_password&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;先运行一遍确保没有报错，然后打开右侧的&amp;quot;maven&amp;quot;→&amp;quot;ruoyi&amp;quot;→&amp;quot;Lifecycle&amp;quot;→&amp;quot;package&amp;quot;，然后等待打包完成，就可以在左侧的&amp;quot;ruoyi-admin&amp;quot;→&amp;quot;target&amp;quot; 看到&amp;quot;ruoyi-admin.jar&amp;quot;了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E6%89%93%E5%8C%85%E8%8B%A5%E4%BE%9D.webp&amp;quot; alt=&amp;quot;打包若依.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后右键&amp;quot;ruoyi-admin.jar&amp;quot;→&amp;quot;Open in&amp;quot;→&amp;quot;Explorer&amp;quot;,你就看到若依的jar包啦&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E6%96%B0%E5%BB%BA%E9%83%A8%E7%BD%B2%E7%9B%AE%E5%BD%95&amp;quot;&amp;gt;新建部署目录&amp;lt;/h3&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;mkdir -p /opt/deploy/ruoyi/{api,web}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;把你的若依jar包放进api里&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E5%90%AF%E5%8A%A8%E8%8B%A5%E4%BE%9D%E9%A1%B9%E7%9B%AE&amp;quot;&amp;gt;启动若依项目&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;在 target 目录下运行：&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;java -jar ruoyi-admin.jar&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;此时后端已经准备完毕，我们接下来准备前端&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;将ruoyi-vue里的ruoyi-ui打开，然后&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;1、安装依赖包，运行 RUOYI-VUE/bin/package.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;2、打包构建，运行 RUOYI-VUE/bin/build.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;（前提：已安装nodejs和yarn）&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF01.webp&amp;quot; alt=&amp;quot;部署前端01.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后把这web文件放这里边&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;/opt/deploy/ruoyi/web&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF02.webp&amp;quot; alt=&amp;quot;部署前端02.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E9%85%8D%E7%BD%AEnginx&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;配置Nginx&amp;lt;/span&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;创建新的配置文件：&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;sudo vi /etc/nginx/conf.d/ruoyi.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;添加以下内容：&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;server {
    listen 80;
    server_name your_domain_or_ip;

    location / {
        proxy_pass http://localhost:8080;  # 若依默认端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;然后Esc → ： → wq&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E9%87%8D%E5%90%AF-nginx&amp;quot;&amp;gt;&amp;lt;span fontsize=&amp;quot;&amp;quot; color=&amp;quot;&amp;quot;&amp;gt;重启 Nginx&amp;lt;/span&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code class=&amp;quot;language-Shell&amp;quot;&amp;gt;sudo systemctl restart nginx&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;h3 style=&amp;quot;&amp;quot; id=&amp;quot;%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C&amp;quot;&amp;gt;最终效果&amp;lt;/h3&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;最后，打开浏览器，访问 http://your_domain_or_ip，就可以看到若依的登录界面了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%89%8D%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;前端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%90%8E%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;后端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
  datasource:
    url: jdbc:mysql://localhost:3306/ruoyi?useUnicode=true&amp;amp;amp;characterEncoding=utf8&amp;amp;amp;serverTimezone=UTC
    username: ruoyiuser
    password: your_password&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;先运行一遍确保没有报错，然后打开右侧的&amp;quot;maven&amp;quot;→&amp;quot;ruoyi&amp;quot;→&amp;quot;Lifecycle&amp;quot;→&amp;quot;package&amp;quot;，然后等待打包完成，就可以在左侧的&amp;quot;ruoyi-admin&amp;quot;→&amp;quot;target&amp;quot; 看到&amp;quot;ruoyi-admin.jar&amp;quot;了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E6%89%93%E5%8C%85%E8%8B%A5%E4%BE%9D.webp&amp;quot; alt=&amp;quot;打包若依.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后右键&amp;quot;ruoyi-admin.jar&amp;quot;→&amp;quot;Open in&amp;quot;→&amp;quot;Explorer&amp;quot;,你就看到若依的jar包啦&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;新建部署目录&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;mkdir -p /opt/deploy/ruoyi/{api,web}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;把你的若依jar包放进api里&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;启动若依项目：&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;在 target 目录下运行：&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;java -jar ruoyi-admin.jar&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;此时后端已经准备完毕，我们接下来准备前端&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;将ruoyi-vue里的ruoyi-ui打开，然后&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;1、安装依赖包，运行 RUOYI-VUE/bin/package.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;2、打包构建，运行 RUOYI-VUE/bin/build.bat&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;（前提：已安装nodejs和yarn）&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF01.webp&amp;quot; alt=&amp;quot;部署前端01.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;然后把这web文件放这里边&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;/opt/deploy/ruoyi/web&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E9%83%A8%E7%BD%B2%E5%89%8D%E7%AB%AF02.webp&amp;quot; alt=&amp;quot;部署前端02.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;配置Nginx&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;创建新的配置文件：&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;sudo vi /etc/nginx/conf.d/ruoyi.conf&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;添加以下内容：&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;server {
    listen 80;
    server_name your_domain_or_ip;

    location / {
        proxy_pass http://localhost:8080;  # 若依默认端口
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;然后Esc → ： → wq&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;font-size: 11ptpx&amp;quot;&amp;gt;重启 Nginx：&amp;lt;/span&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;sudo systemctl restart nginx&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;最后，打开浏览器，访问 http://your_domain_or_ip，就可以看到若依的登录界面了。&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%89%8D%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;前端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;p style=&amp;quot;&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/upload/%E5%90%8E%E7%AB%AF%E6%88%90%E5%8A%9F.webp&amp;quot; alt=&amp;quot;后端成功.png&amp;quot; width=&amp;quot;100%&amp;quot; height=&amp;quot;100%&amp;quot; style=&amp;quot;display: inline-block&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</description>
        </item>
        <item>
        <title>好朋友们</title>
        <link>https://qiuyingtyan.top/%E5%8F%8B%E9%93%BE/</link>
        <pubDate>Tue, 12 Nov 2024 15:56:00 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/%E5%8F%8B%E9%93%BE/</guid>
        <description>&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://blog.iam57.com/&#34;&gt;五七の博客&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://blog.angelcoc.icu/&#34;&gt;Angel&#39;s Blog - 赛博小窝&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://blyrin.cn&#34; target=&#34;_self&#34; rel=&#34;&#34;&gt;blyrin&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;http://blog.qsdream.site/&#34;&gt;拾壹博客-一个专注于技术分享的博客平台&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;a href=&#34;https://blog.zwanan.top/&#34;&gt;Zwanan&#39;s Blog&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style=&#34;&#34;&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>归档</title>
        <link>https://qiuyingtyan.top/archives/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/archives/</guid>
        <description></description>
        </item>
        <item>
        <title>搜索</title>
        <link>https://qiuyingtyan.top/search/</link>
        <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
        
        <guid>https://qiuyingtyan.top/search/</guid>
        <description></description>
        </item>
        
    </channel>
</rss>
