<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>编程随笔</title><link>https://xiaoying.org.cn/</link><description>Recent content on 编程随笔</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Thu, 12 Mar 2026 21:36:27 +0800</lastBuildDate><atom:link href="https://xiaoying.org.cn/index.xml" rel="self" type="application/rss+xml"/><item><title>vuepress搭建网站</title><link>https://xiaoying.org.cn/pages/469c69/</link><pubDate>Tue, 21 Nov 2023 12:42:43 +0000</pubDate><guid>https://xiaoying.org.cn/pages/469c69/</guid><description>&lt;h1 id="heading"&gt;使用本项目 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="heading-1"&gt;克隆到本地 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9bf2502" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git clone https://github.com/liyao52033/vuepress-default.git

yarn install&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;脚本说明 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d37ae52" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;#34;scripts&amp;#34;: {
 &amp;#34;docs:dev&amp;#34;: &amp;#34;vuepress dev docs&amp;#34;, //启动项目
 &amp;#34;docs:build&amp;#34;: &amp;#34;vuepress build docs&amp;#34;, // 打包项目
 &amp;#34;docs:nav&amp;#34;: &amp;#34;vuepress nav docs -f&amp;#34; , // 生成导航栏与侧边栏
 &amp;#34;deploy&amp;#34;: &amp;#34;./docs/.vuepress/deploy.sh&amp;#34;, //部署到github.io
 &amp;#34;push&amp;#34;: &amp;#34;./docs/push.sh&amp;#34; //推送到github
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;启动项目 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b4f3568" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn run docs:dev&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="docs"&gt;在docs构建目录如下 &lt;a href="#docs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6aa52a9" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;docs
├─ README.md
├─ contact.md
├─ about.md
├─ foo/
│ ├─ test
│ ├─ ├─ README.md 
│ ├─ README.md
│ ├─ one.md
│ └─ two.md
└─ bar/
 ├─ README.md
 ├─ three.md
 └─ four.md&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;文件夹可以嵌套，但每个文件夹都必须有README目录，不然会报404&lt;/p&gt;</description></item><item><title>引入第三方组件库</title><link>https://xiaoying.org.cn/pages/fa7166/</link><pubDate>Wed, 29 Nov 2023 01:14:36 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fa7166/</guid><description>&lt;p&gt;当你在开发一个 VuePress 应用时，由于所有的页面在生成静态 HTML 时都需要通过 Node.js 服务端渲染，因此所有的 Vue 相关代码都应当遵循 &lt;a href="https://ssr.vuejs.org/zh/universal.html" rel="external" target="_blank"&gt;编写通用代码 (opens new window)&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;的要求。简而言之，请确保只在 &lt;code&gt;beforeMount&lt;/code&gt; 或者 &lt;code&gt;mounted&lt;/code&gt; 访问浏览器 / DOM 的 API。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="41de1cc" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// docs/.vuepress/enhanceApp.js

export default ({
 Vue,
 options,
 router,
 siteData,
}) =&amp;gt; {
// FIXME:解决加载 import &amp;#39;v-dialogs&amp;#39; 报错的问题
 Vue.mixin({
 mounted() {
 let dialog = require(&amp;#39;v-dialogs&amp;#39;)
 Vue.use(dialog)
 },
 });
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;如果你的模块通过 &lt;code&gt;export default&lt;/code&gt; 导出一个 Vue 组件，那么你可以动态注册它：&lt;/p&gt;</description></item><item><title>优化改进</title><link>https://xiaoying.org.cn/pages/6c372a/</link><pubDate>Thu, 07 Dec 2023 22:20:33 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6c372a/</guid><description>&lt;h2 id="500kb"&gt;打包报超出500kB &lt;a href="#500kb" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;执行 npm run build 打包出现如下问题
&lt;code&gt;[BABEL] Note: The code generator has deoptimised the styling of docs test.md as it exceeds the max of 500KB&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style='color:red;font-size:30px;'&gt;解决方案如下&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.提高参 数 &amp;ndash;max_old_space_size （提高到 102400）&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6c9bb5a" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;#34;scripts&amp;#34;: {
 &amp;#34;docs:build&amp;#34;: &amp;#34;set NODE_OPTIONS=--openssl-legacy-provider &amp;amp;&amp;amp; node -- max_old_space_size=102400 ./node_modules/vuepress/cli.js build docs&amp;#34;
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;2.项目根目录创建 .babelrc 并添加如下代码&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ed4ff7e" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;{
 &amp;#34;compact&amp;#34;: false,
 &amp;#34;presets&amp;#34;: [&amp;#34;env&amp;#34;, &amp;#34;react&amp;#34;, &amp;#34;stage-0&amp;#34;],
 &amp;#34;plugins&amp;#34;: [
 &amp;#34;transform-runtime&amp;#34;
 ]
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;然后执行如下docs:build命令即可&lt;/p&gt;</description></item><item><title>站点信息模块</title><link>https://xiaoying.org.cn/pages/5cccbb/</link><pubDate>Tue, 23 Apr 2024 10:31:17 +0000</pubDate><guid>https://xiaoying.org.cn/pages/5cccbb/</guid><description>&lt;p&gt;::: tip 说明&lt;/p&gt;
&lt;p&gt;本内容介绍如何搭建本站首页的站点信息，以及每篇文章的浏览量统计，主要改动了文章页的浏览量统计，其余部分参考&lt;a href="https://notes.youngkbt.cn/about/website/info/" rel="external" target="_blank"&gt;站点信息模块&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2 id="heading"&gt;前言 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本内容将在首页和每篇的文章页加入了一些元素，目前适用版本是 Vdoing v1.x。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;如果你想集成到其他 Vuepress 主题，那么要添加卡片样式，修改挂载元素即可（建议先按照步骤完成一次再考虑集成）。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;为什么添加卡片样式&lt;/strong&gt;？本模块的站点信息是基于 Vdoing 自带的卡片样式，模块并没有添加任何卡片样式，所以想集成到其他主题，则需要参考 Vdoing 卡片样式进行添加，或者按照自己喜欢的样式进行添加&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么修改挂载元素&lt;/strong&gt;？本模块的挂载元素是基于 Vdoing 标签提供的 class 或 id，而其他主题的标签不一样，所以自行进行调试&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本模块的所有 &lt;strong&gt;功能&lt;/strong&gt; 支持大部分 Vuepress 主题，但是如何将所有功能展示到其他主题页面合适的地方，以及展示的样式等 DOM 技术，需要自己适配。&lt;/p&gt;</description></item><item><title>本站主题包</title><link>https://xiaoying.org.cn/pages/9d746f/</link><pubDate>Sat, 14 Jun 2025 19:07:08 +0000</pubDate><guid>https://xiaoying.org.cn/pages/9d746f/</guid><description>&lt;h2 id="github"&gt;github地址 &lt;a href="#github" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



&lt;div class="row g-4 mb-3 mt-1 me-1 d-flex"&gt;
 
 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/vitepress-teek" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/20250725164502996.png" class="card-img-top mt-2" alt="本站主题包" /&gt;
 
 &lt;span class="title mt-2"&gt;本站主题包&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-primary position-absolute top-0 end-0"&gt;vitepress主题&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;基于teek的 Vitepress主题，只需少量配置即可使用，支持脚手架安装。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 

 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/Kele-Bingtang/vitepress-theme-teek" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/20250725163209174.png" class="card-img-top mt-2" alt="teek主题" /&gt;
 
 &lt;span class="title mt-2"&gt;teek主题&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-secondary position-absolute top-0 end-0"&gt;vitepress主题&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;Teek 是一个轻量、简洁高效、灵活配置、易于扩展的 VitePress 主题。&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 

 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/hugopress" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/20251004194533736.png" class="card-img-top mt-2" alt="本站主题包(hugo版)" /&gt;
 
 &lt;span class="title mt-2"&gt;本站主题包(hugo版)&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-info position-absolute top-0 end-0"&gt;hugo主题&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;基于 Hugo 框架，具备极速编译、跨平台支持、强大内容管理与纯静态部署优势的文档站&lt;/p&gt;</description></item><item><title>快速开始</title><link>https://xiaoying.org.cn/pages/571de5/</link><pubDate>Fri, 28 Mar 2025 10:40:47 +0000</pubDate><guid>https://xiaoying.org.cn/pages/571de5/</guid><description>&lt;h2 id="heading"&gt;依赖引用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;提示&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;&lt;p&gt;依赖可能非最新版本，请前往maven获取最新版本&lt;/p&gt;
&lt;p&gt;&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/common-spring-boot-starter" rel="external" target="_blank"&gt;Spring Boot 2&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;地址&lt;/p&gt;</description></item><item><title>BackTop</title><link>https://xiaoying.org.cn/pages/1a7d12/</link><pubDate>Wed, 26 Mar 2025 06:54:48 +0000</pubDate><guid>https://xiaoying.org.cn/pages/1a7d12/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;网页往下滑一定高度后点击可直接返回顶部，可注册为全局组件&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8bafe57" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
 import { BackTop } from &amp;#34;liyao-vue-common&amp;#34;
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;BackTop /&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>组件安装</title><link>https://xiaoying.org.cn/pages/fe4521/</link><pubDate>Tue, 25 Feb 2025 07:51:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fe4521/</guid><description>&lt;p&gt;基于 Vue 3 和 Element Plus 的上传组件库。&lt;/p&gt;
&lt;h2 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b79ffb4" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;pnpm install liyao-vue-common&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;使用方法 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;全局引入 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5e3beac" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { createApp } from &amp;#39;vue&amp;#39;
import App from &amp;#39;./App.vue&amp;#39;
import liyaoVueCommon from &amp;#39;liyao-vue-common&amp;#39;
import &amp;#39;liyao-vue-common/dist/style.css&amp;#39;

const app = createApp(App)
app.use(liyaoVueCommon)
app.mount(&amp;#39;#app&amp;#39;)&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;然后在组件中直接使用：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8b9e613" class="language-html wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;uploadCos :uploadFileApi=&amp;#34;yourUploadFunction&amp;#34; /&amp;gt;
 &amp;lt;uploadLocal :importFile=&amp;#34;yourImportFunction&amp;#34; /&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-3"&gt;按需引入 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2246f2f" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { uploadCos, uploadLocal } from &amp;#39;liyao-vue-common&amp;#39;
import &amp;#39;liyao-vue-common/dist/style.css&amp;#39;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;然后在组件中注册和使用：&lt;/p&gt;</description></item><item><title>kiftd使用docker部署</title><link>https://xiaoying.org.cn/pages/e1a10d/</link><pubDate>Fri, 24 Nov 2023 10:55:40 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e1a10d/</guid><description>&lt;h2 id="usrlocalkiftd"&gt;在/usr/local/kiftd下新建文件夹，后续文件都在此目录 &lt;a href="#usrlocalkiftd" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2 id="kiftdusrlocalkiftd"&gt;上传&lt;a href="https://kohgylw.gitee.io/" rel="external" target="_blank"&gt;kiftd&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;文件到/usr/local/kiftd下 &lt;a href="#kiftdusrlocalkiftd" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2 id="dockerfile"&gt;新建Dockerfile如下 &lt;a href="#dockerfile" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;::: tip 提示&lt;/p&gt;
&lt;p&gt;Dockerfile必须跟文件同一目录，如果只有一个jar包，则跟jar包同一个目录；&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9f95fb8" class="language-dockerfile wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 使用jdk8镜像
FROM openjdk:8-jre-alpine

# 设置工作目录
WORKDIR /app

# 设置时区，否则跟北京时间有8个小时时间差
RUN rm -f /etc/localtime \
&amp;amp;&amp;amp; ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
&amp;amp;&amp;amp; echo &amp;#34;Asia/Shanghai&amp;#34; &amp;gt; /etc/timezone

# 将kiftd-1.1.1-release文件夹拷贝到工作目录下,最后一个/表示是目录
# 如果只有一个jar包，则为COPY kiftd.jar /app/kiftd.jar
COPY kiftd-1.1.1-release/ /app/kiftd-1.1.1-release/

# 暴露端口
EXPOSE 8080

# 启动程序，如果只有一个jar包，则为 &amp;#34;/app/kiftd.jar&amp;#34;
CMD [&amp;#34;java&amp;#34;,&amp;#34;-jar&amp;#34;,&amp;#34;/app/kiftd-1.1.1-release/kiftd.jar&amp;#34;,&amp;#34;-start&amp;#34;]&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="workdir-appvolume-tmp"&gt;WORKDIR /app跟VOLUME /tmp区别 &lt;a href="#workdir-appvolume-tmp" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;WORKDIR&lt;/code&gt; 和 &lt;code&gt;VOLUME&lt;/code&gt; 是 Dockerfile 中两个不同的指令，它们分别用于不同的目的。&lt;/p&gt;</description></item><item><title>增加登录页面</title><link>https://xiaoying.org.cn/pages/634ec7/</link><pubDate>Tue, 28 Nov 2023 15:13:36 +0000</pubDate><guid>https://xiaoying.org.cn/pages/634ec7/</guid><description>&lt;h2 id="heading"&gt;安装插件 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;安装&lt;code&gt;v-dialogs&lt;/code&gt;模态对话框插件&lt;/p&gt;
&lt;p&gt;:::: el-tabs&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=yarn&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b299366" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add v-dialogs -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::: el-tab-pane label=npm&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="bac07f9" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm i v-dialogs -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::::&lt;/p&gt;
&lt;h2 id="heading-1"&gt;创建登录表单文件 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;添加&lt;code&gt;helper.js&lt;/code&gt;&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b97cc61" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;export const STORAGE_KEY = &amp;#39;employee-auth&amp;#39;

// Do user authorization verify
export function checkAuth () {
 const auth = JSON.parse(localStorage.getItem(STORAGE_KEY))
 return auth &amp;amp;&amp;amp; Object.keys(auth).length
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;添加&lt;code&gt;Login.vue&lt;/code&gt;登录表单文件，显示在模态对话框中&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="16a9e5f" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;login-container&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;login-form&amp;#34;&amp;gt;
	&amp;lt;Date /&amp;gt;
	&amp;lt;div class=&amp;#34;form-row&amp;#34;&amp;gt;
		&amp;lt;div class=&amp;#34;form-header&amp;#34;&amp;gt;账号&amp;lt;/div&amp;gt;
		&amp;lt;input type=&amp;#34;text&amp;#34; class=&amp;#34;form-control&amp;#34; v-model=&amp;#34;username&amp;#34;&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div class=&amp;#34;form-row&amp;#34;&amp;gt;
		&amp;lt;div class=&amp;#34;form-header&amp;#34;&amp;gt;密码&amp;lt;/div&amp;gt;
		&amp;lt;input type=&amp;#34;password&amp;#34; class=&amp;#34;form-control&amp;#34; v-model=&amp;#34;password&amp;#34;&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div class=&amp;#34;btn-row&amp;#34;&amp;gt;
		&amp;lt;button class=&amp;#34;btn&amp;#34; @click=&amp;#34;login&amp;#34;&amp;gt;
		登录
		&amp;lt;/button&amp;gt;
	&amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { STORAGE_KEY } from &amp;#39;../login/helper&amp;#39;

export default {
 name: &amp;#39;Login&amp;#39;,
 data () {
	return {
	 username: &amp;#39;&amp;#39;,
	 password: &amp;#39;&amp;#39;
	}
 },
 methods: {
	login() {
		 let { expiration, token } = this.$themeConfig.loginInfo

		// 如果用户名和密码正确
		if (this.username &amp;amp;&amp;amp; this.password) {
			// 创建用户数据对象
			const data = JSON.stringify({
				name: this.username,
				time: Math.round(new Date().getTime()/1000),
				expire: 86400 * expiration,
				accesskey: token
			})
			// 将用户数据存储到本地存储
			window.localStorage.setItem(STORAGE_KEY, data)
			// 跳转到首页
			this.$router.push(&amp;#39;/&amp;#39;, () =&amp;gt; {
				// 显示登录成功提示
				dialog.DialogToast(&amp;#39;登录成功&amp;#39;, {
					messageType: &amp;#39;success&amp;#39;,
					position: &amp;#39;topCenter&amp;#39;,
					closeTime: 3
				})
			}, (error) =&amp;gt; {
				// 显示系统错误提示
				dialog.DialogToast(&amp;#39;系统错误&amp;#39;, {
					messageType: &amp;#39;error&amp;#39;,
					position: &amp;#39;topCenter&amp;#39;,
					closeTime: 3
				})
			})
		} else {
			// 显示账号或密码错误提示
			dialog.DialogToast(&amp;#39;账号或密码错误!&amp;#39;, {
				messageType: &amp;#39;error&amp;#39;,
				position: &amp;#39;topCenter&amp;#39;,
				closeTime: 3
			})
		}
	}
 }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&amp;#34;stylus&amp;#34;&amp;gt;
.login-container {
 width: 100%;
 height: 100vh;
 background-color: #2d3a4b;
}
.form-row {
 display: flex;
 flex-direction: row;
 margin-top: 1rem;
}
.login-form {
 padding: 1rem;
 display: flex;
 flex-direction: column;
 box-sizing: border-box;
 background-color: #2d3a4b;
 width:50%;
 position:absolute;
 left:50%; /* 定位父级的50% */
 top:50%;
 transform: translate(-50%,-50%); /*自己的50% */
}

.login-form .btn-row {
 margin: 2rem auto;
}

.login-form .btn {
 padding: 0.6rem 2rem;
 outline: none;
 background-color: #60C084;
 color: white;
 border: 0;
 width: 13rem;
}

.login-form .form-header {
 color: #f08d49;
 margin-bottom: 0.5rem;
 width: 3rem;
 padding-top: .5rem;
}

.login-form .form-control {
 padding: 0.6rem;
 border: 2px solid #ddd;
 margin-bottom: 0.5rem;
 box-sizing: border-box;
 outline: none;
 flex: 1;
 transition: border 0.2s ease;
}

.login-form .form-control:focus {
 border: 2px solid #aaa;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="vuepress-"&gt;VuePress 配置 &lt;a href="#vuepress-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;添加&lt;code&gt;enhanceApp.js&lt;/code&gt;文件于&lt;code&gt;/.vuepress&lt;/code&gt;&lt;/p&gt;</description></item><item><title>添加登录并启用全局前置守卫</title><link>https://xiaoying.org.cn/pages/aa8477/</link><pubDate>Tue, 16 Jan 2024 17:32:13 +0000</pubDate><guid>https://xiaoying.org.cn/pages/aa8477/</guid><description>&lt;h2 id="heading"&gt;新增登录页面 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在&lt;mark&gt;.vuepress/components&lt;/mark&gt;新增&lt;mark&gt;Login.vue&lt;/mark&gt;&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0a0da3b" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;login-container&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;login-form&amp;#34;&amp;gt;
	&amp;lt;Date /&amp;gt;
	&amp;lt;div class=&amp;#34;form-row&amp;#34;&amp;gt;
		&amp;lt;div class=&amp;#34;form-header&amp;#34;&amp;gt;账号&amp;lt;/div&amp;gt;
		&amp;lt;input type=&amp;#34;text&amp;#34; class=&amp;#34;form-control&amp;#34; v-model=&amp;#34;username&amp;#34;&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div class=&amp;#34;form-row&amp;#34;&amp;gt;
		&amp;lt;div class=&amp;#34;form-header&amp;#34;&amp;gt;密码&amp;lt;/div&amp;gt;
		&amp;lt;input type=&amp;#34;password&amp;#34; class=&amp;#34;form-control&amp;#34; v-model=&amp;#34;password&amp;#34;&amp;gt;
	&amp;lt;/div&amp;gt;
	&amp;lt;div class=&amp;#34;btn-row&amp;#34;&amp;gt;
		&amp;lt;button class=&amp;#34;btn&amp;#34; @click=&amp;#34;login&amp;#34;&amp;gt;
		登录
		&amp;lt;/button&amp;gt;
	&amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import { STORAGE_KEY } from &amp;#39;../login/helper&amp;#39;
import { DialogToast } from &amp;#39;v-dialogs&amp;#39;

export default {
 data () {
	return {
	 username: &amp;#39;&amp;#39;,
	 password: &amp;#39;&amp;#39;
	}
 },
 methods: {
	 login() {
		 let { time, token } = this.$themeConfig.loginInfo
	 if (this.username &amp;amp;&amp;amp; this.password ) {
		const data = JSON.stringify({
		 name: this.username,
		 time: Math.round(new Date().getTime()/1000),
		 expire: 86400 * time,
		 accesskey: token
		})
		window.localStorage.setItem(STORAGE_KEY, data)
		this.$router.push({ name: &amp;#39;v-413f20b7&amp;#39; }, () =&amp;gt; {
			DialogToast(&amp;#39;登录成功&amp;#39;, {
				messageType: &amp;#39;success&amp;#39;,
				position: &amp;#39;topCenter&amp;#39;,
				closeTime: 3
			})
		}, (error) =&amp;gt; {
			DialogToast(&amp;#39;系统错误&amp;#39;, {
				messageType: &amp;#39;error&amp;#39;,
				position: &amp;#39;topCenter&amp;#39;,
				closeTime: 3
			})
		})		
	 } else {
		DialogToast(&amp;#39;账号或密码错误!&amp;#39;, {
			messageType: &amp;#39;error&amp;#39;,
			position: &amp;#39;topCenter&amp;#39;,
			closeTime: 3 
		})
	 }
	}
 }
}
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&amp;#34;stylus&amp;#34;&amp;gt;
.login-container {
 width: 100%;
 height: 100vh;
 background-color: #2d3a4b;
}
.form-row {
 display: flex;
 flex-direction: row;
 margin-top: 1rem;
}
.login-form {
 padding: 1rem;
 display: flex;
 flex-direction: column;
 box-sizing: border-box;
 background-color: #2d3a4b;
 width:50%;
 position:absolute;
 left:50%; /* 定位父级的50% */
 top:50%;
 transform: translate(-50%,-50%); /*自己的50% */
}

.login-form .btn-row {
 margin: 2rem auto;
}

.login-form .btn {
 padding: 0.6rem 2rem;
 outline: none;
 background-color: #60C084;
 color: white;
 border: 0;
 width: 13rem;
}

.login-form .form-header {
 color: #f08d49;
 margin-bottom: 0.5rem;
 width: 3rem;
 padding-top: .5rem;
}

.login-form .form-control {
 padding: 0.6rem;
 border: 2px solid #ddd;
 margin-bottom: 0.5rem;
 box-sizing: border-box;
 outline: none;
 flex: 1;
 transition: border 0.2s ease;
}

.login-form .form-control:focus {
 border: 2px solid #aaa;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="login"&gt;新增登录页面路由/login &lt;a href="#login" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d914d4d" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;module.exports = {
 ...
 
 additionalPages: [
 {
 path: &amp;#39;/login/&amp;#39;,
 frontmatter: {
 layout: &amp;#39;Login&amp;#39;, //.vuepress/components新增的页面，名称得同名
 article: false // 设置为非文章页
 }
 }
 ],
 
 themeConfig: {
 ...
 }
 
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="helperjs"&gt;添加登录验证逻辑&lt;mark&gt;helper.js&lt;/mark&gt; &lt;a href="#helperjs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="958f2c5" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;export const STORAGE_KEY = &amp;#39;employee-auth&amp;#39;

export function checkAuth() {
 // 通过 localStorage 对象从浏览器本地存储中获取指定键（STORAGE_KEY）对应的值
 // 使用 JSON.parse 将其转换为对象。
 const auth = JSON.parse(localStorage.getItem(STORAGE_KEY))
 // Object.keys(auth) 返回一个由对象的键组成的数组，而 .length 属性表示数组的长度，因此这个条件检查对象是否非空。
 // 返回值是一个布尔值。如果 auth 存在且至少包含一个键，那么表达式的结果为 true，否则为 false。
 return auth &amp;amp;&amp;amp; Object.keys(auth).length 
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;添加路由守卫 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;安装&lt;mark&gt;v-dialogs&lt;/mark&gt;模态对话框插件&lt;/p&gt;</description></item><item><title>Cos对象存储</title><link>https://xiaoying.org.cn/pages/89cd20/</link><pubDate>Fri, 28 Mar 2025 11:46:49 +0000</pubDate><guid>https://xiaoying.org.cn/pages/89cd20/</guid><description>&lt;h2 id="heading"&gt;引用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="56c6295" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@RestController
@Slf4j
@RequestMapping(&amp;#34;/cos&amp;#34;)
public class CosController {
 ...
 @Resource
 private CosService cosService;
 ...
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;文件上传 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="772b2cb" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/upload&amp;#34;)
@Operation(summary = &amp;#34;文件上传&amp;#34;)
public BaseResponse&amp;lt;String&amp;gt; upload(MultipartFile file, String biz) {
 return cosService.uploadObject(file, biz);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;文件下载到本地 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="950596f" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; @PostMapping(&amp;#34;/downloadLocal&amp;#34;)
 @Operation(summary = &amp;#34;文件下载到本地&amp;#34;)
 public void downloadToLocal(String url, String localFilePath) {
 cosService.download(url, localFilePath);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;文件下载到流 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8f9c328" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; @PostMapping(&amp;#34;/download&amp;#34;)
 @Operation(summary = &amp;#34;文件下载到流&amp;#34;)
 public byte[] download(String url) throws IOException {
 return cosService.getObject(url);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;文件删除 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9639a26" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/delete&amp;#34;)
@Operation(summary = &amp;#34;文件删除&amp;#34;)
public BaseResponse&amp;lt;String&amp;gt; delete(String url) {
 return cosService.deleteObject(url);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-5"&gt;完整代码 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="65efdfb" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@RestController
@Slf4j
@RequestMapping(&amp;#34;/cos&amp;#34;)
public class CosController {

 @Resource
 private CosService cosService;

 @PostMapping(&amp;#34;/upload&amp;#34;)
 @Operation(summary = &amp;#34;文件上传&amp;#34;)
 public BaseResponse&amp;lt;String&amp;gt; upload(MultipartFile file, String biz) {

 return cosService.uploadObject(file, biz);

 }

 @PostMapping(&amp;#34;/downloadLocal&amp;#34;)
 @Operation(summary = &amp;#34;文件下载到本地&amp;#34;)
 public void downloadToLocal(String url, String localFilePath) {

 cosService.download(url, localFilePath);

 }

 @PostMapping(&amp;#34;/download&amp;#34;)
 @Operation(summary = &amp;#34;文件下载到流&amp;#34;)
 public byte[] download(String url) throws IOException {

 return cosService.getObject(url);

 }

 @PostMapping(&amp;#34;/delete&amp;#34;)
 @Operation(summary = &amp;#34;文件删除&amp;#34;)
 public BaseResponse&amp;lt;String&amp;gt; delete(String url) {

 return cosService.deleteObject(url);

 }


}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>GlobalTip</title><link>https://xiaoying.org.cn/pages/6ea39c/</link><pubDate>Wed, 26 Mar 2025 06:54:48 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6ea39c/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在页面上出现时间提示及问候语，3秒后自动消失，可注册为全局组件，vitepress使用时可插入doc-top插槽&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="28dd064" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
 import { GlobalTip } from &amp;#34;liyao-vue-common&amp;#34;
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;GlobalTip /&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>基于本库开发新组件</title><link>https://xiaoying.org.cn/pages/a3c3b7/</link><pubDate>Tue, 25 Mar 2025 07:54:43 +0000</pubDate><guid>https://xiaoying.org.cn/pages/a3c3b7/</guid><description>&lt;h2 id="heading"&gt;注册新组件 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;src/components&lt;/code&gt; 目录下创建新组件，然后在入口文件 &lt;code&gt;src/index.ts&lt;/code&gt; 中导入并注册该组件。&lt;/p&gt;

&lt;nav&gt;
	&lt;div class="nav nav-tabs" id="nav-tab" role="tablist"&gt;

		
		
		
		

		

		&lt;a class="nav-link active"
		 id="feadbcTab" data-bs-toggle="tab" data-bs-target="#feadbc"
		 type="button" role="tab" aria-controls="feadbc" aria-selected="true"&gt;src/index.ts&lt;/a&gt;

		

	&lt;/div&gt;
&lt;/nav&gt;

&lt;div class="tab-content" id="nav-tab-content"&gt;

	







&lt;div class="tab-pane fade show active" id="feadbc" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="90a5933" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 导入新组件
import uploadCos from &amp;#39;../Upload/uploadCos.vue&amp;#39;;
import uploadLocal from &amp;#39;../Upload/uploadLocal.vue&amp;#39;;
import newComponent from &amp;#39;../Your/NewComponent.vue&amp;#39;; // 添加新组件导入

// 组件注册表 - 只需要在这里添加新组件
const componentList = {
 uploadCos,
 uploadLocal,
 newComponent // 添加新组件到注册表
};&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;



&lt;/div&gt;
&lt;h2 id="heading-1"&gt;添加类型声明 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;types/index.d.ts&lt;/code&gt; 文件中添加类型声明，需要在&lt;strong&gt;四个地方&lt;/strong&gt;添加&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="84f0802" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 1. 导入时的组件类型定义
declare module &amp;#39;liyao-vue-common&amp;#39; {
 export const uploadCos: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 export const uploadLocal: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 export const newComponent: DefineComponent&amp;lt;{}, {}, any&amp;gt;; // 添加新组件类型
 export const install: (app: App) =&amp;gt; void;
}

// 2. Vue 全局组件类型定义
declare module &amp;#39;vue&amp;#39; {
 export interface GlobalComponents {
 uploadCos: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 uploadLocal: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 newComponent: DefineComponent&amp;lt;{}, {}, any&amp;gt;; // 添加全局组件类型
 }
}

// 3. 组件文件模块声明
declare module &amp;#39;@/components/Upload/uploadCos.vue&amp;#39; {
 const component: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 export default component;
}

declare module &amp;#39;@/components/Upload/uploadLocal.vue&amp;#39; {
 const component: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 export default component;
}

// 添加新组件的模块声明
declare module &amp;#39;@/components/Your/NewComponent.vue&amp;#39; {
 const component: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 export default component;
}

// 4. 默认导出
declare const _default: {
 install: (app: App) =&amp;gt; void;
 uploadCos: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 uploadLocal: DefineComponent&amp;lt;{}, {}, any&amp;gt;;
 newComponent: DefineComponent&amp;lt;{}, {}, any&amp;gt;; // 添加默认导出类型
};&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;更新版本号并发布: &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c62eca8" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 修改 package.json 中的版本号
pnpm pub&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>Captcha验证码使用</title><link>https://xiaoying.org.cn/pages/e40993/</link><pubDate>Fri, 28 Mar 2025 11:46:03 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e40993/</guid><description>&lt;h2 id="heading"&gt;引用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先在项目中引用EasyCaptchaService&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b0f1246" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;public class CaptchaController {
 ...
 @Resource
 private EasyCaptchaService captchaService;
 ...
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;生成验证码 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4506c17" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/get&amp;#34;)
@Operation(summary = &amp;#34;生成验证码&amp;#34;)
public BaseResponse&amp;lt;CaptchaResult&amp;gt; captcha() {
 return captchaService.generateCaptcha();
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;校验验证码 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c268e80" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/check&amp;#34;)
@Operation(summary = &amp;#34;校验验证码&amp;#34;)
public BaseResponse&amp;lt;String&amp;gt; verifyCaptcha(@RequestBody CaptchaCheck CaptchaCheck){
 String verifyCode = CaptchaCheck.getVerifyCode();
 String verifyCodeKey = CaptchaCheck.getVerifyCodeKey();
 return captchaService.verifyCaptcha(verifyCode, verifyCodeKey);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;完整代码 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="89e5fa6" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@RestController
@Slf4j
@RequestMapping(&amp;#34;/captcha&amp;#34;)
public class CaptchaController {

 @Resource
 private EasyCaptchaService captchaService;

 @PostMapping(&amp;#34;/get&amp;#34;)
 @Operation(summary = &amp;#34;生成验证码&amp;#34;)
 public BaseResponse&amp;lt;CaptchaResult&amp;gt; captcha() {
 return captchaService.generateCaptcha();
 }

 @PostMapping(&amp;#34;/check&amp;#34;)
 @Operation(summary = &amp;#34;校验验证码&amp;#34;)
 public BaseResponse&amp;lt;String&amp;gt; verifyCaptcha(@RequestBody CaptchaCheck CaptchaCheck) {
 String verifyCode = CaptchaCheck.getVerifyCode();
 String verifyCodeKey = CaptchaCheck.getVerifyCodeKey();
 return captchaService.verifyCaptcha(verifyCode, verifyCodeKey);

 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>GithubCorner</title><link>https://xiaoying.org.cn/pages/aa29be/</link><pubDate>Thu, 27 Mar 2025 08:30:07 +0000</pubDate><guid>https://xiaoying.org.cn/pages/aa29be/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Github角标&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="170404a" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
 import { GithubCorner } from &amp;#34;liyao-vue-common&amp;#34;
&amp;lt;/script&amp;gt;


&amp;lt;template&amp;gt;
// 需要自己写css确定要放的位置， href为跳转的链接
 &amp;lt;GithubCorner :href=&amp;#34;&amp;#39;https://github.com&amp;#39;&amp;#34;/&amp;gt; 
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;参数 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3d84412" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;const props = defineProps({
 href: {
 type: String,
 default: &amp;#39;&amp;#39;,
 }
})&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>vue3组件封装</title><link>https://xiaoying.org.cn/pages/6fcc8f/</link><pubDate>Mon, 24 Mar 2025 17:21:56 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6fcc8f/</guid><description>&lt;h1 id="vue-3--npm-"&gt;Vue 3 组件封装与 npm 发布指南 &lt;a href="#vue-3--npm-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="heading"&gt;一、概述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Vue 3 提供了强大的组件化能力，通过封装组件，可以实现高度灵活的复用。本文将介绍如何封装两种类型的 Vue 3 组件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;动态插槽组件&lt;/strong&gt;：支持宿主项目按需定义任意数量的插槽。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;普通组件&lt;/strong&gt;：封装一个简单的功能组件，例如一个按钮组件。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们将把这两种组件封装到一个 npm 包中，方便其他开发者下载和使用。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;二、封装组件 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;创建项目结构 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;创建项目文件夹，例如 &lt;code&gt;vue3-components&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;在项目文件夹中初始化 npm 项目：&lt;/li&gt;
&lt;/ol&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="864dfed" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm init -y&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;安装 Vue 3 和其他必要的依赖：&lt;/li&gt;
&lt;/ol&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="af15a9c" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install vue@3&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-3"&gt;编写动态插槽组件 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src&lt;/code&gt; 文件夹中创建动态插槽组件文件，例如 &lt;code&gt;DynamicSlots.vue&lt;/code&gt;：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="01b0a96" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;dynamic-slots&amp;#34;&amp;gt;
 &amp;lt;slot v-for=&amp;#34;(_, name) in $slots&amp;#34; :name=&amp;#34;name&amp;#34; :key=&amp;#34;name&amp;#34; /&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
 name: &amp;#34;DynamicSlots&amp;#34;,
};
&amp;lt;/script&amp;gt;

&amp;lt;style scoped&amp;gt;
.dynamic-slots {
 display: flex;
 flex-direction: column;
 gap: 10px;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-4"&gt;编写普通组件 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src&lt;/code&gt; 文件夹中创建普通组件文件，例如 &lt;code&gt;MyButton.vue&lt;/code&gt;：&lt;/p&gt;</description></item><item><title>自动生成frontmatter</title><link>https://xiaoying.org.cn/pages/3ab292/</link><pubDate>Tue, 18 Mar 2025 00:03:50 +0000</pubDate><guid>https://xiaoying.org.cn/pages/3ab292/</guid><description>&lt;h1 id="vitepress-plugin-setfrontmatter"&gt;vitepress-plugin-setfrontmatter使用 &lt;a href="#vitepress-plugin-setfrontmatter" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="github"&gt;github地址 &lt;a href="#github" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



&lt;div class="row g-4 mb-3 mt-1 me-1 d-flex"&gt;
 
 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/vitepress-plugin-setfrontmatter" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/202503231752583.png" class="card-img-top mt-2" alt="vitepress-plugin-setfrontmatter" /&gt;
 
 &lt;span class="title mt-2"&gt;vitepress-plugin-setfrontmatter&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-primary position-absolute top-0 end-0"&gt;vitepress插件&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;这是一个适用于vitepress的 Vite 插件，vitepress启动时，插件会给指定的 markdown 自动生成frontmatter&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 


&lt;/div&gt;

&lt;style&gt;

 .navcard-container .card {
 background-color: #f6f6f7;
 transition: transform 0.3s ease, box-shadow 0.3s ease;
 border-radius: 10px;
 }

 .navcard-container:hover .card {
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
 transform: translateY(-3px);
 }

 .navcard-container .card-text {
 color: #67676c;
 font-size: 12px;
 overflow: hidden;
 white-space: normal;
 text-overflow: ellipsis;
 }

 .navcard-container .title {
 font-size: 14px;
 font-weight: 600;
 }

 .navcard-container .badge {
 margin: 5px 5px 0 0;
 border-radius: 14px;
 font-size: 9px;
 }

 .navcard-container .card-img-top {
 width: 40px;
 height: 40px;
 border-radius: 50%;
 margin: 0 10px;
 }

 
 html[data-dark-mode] .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html[data-dark-mode] .navcard-container .card-text {
 color: var(--gray-300);
 }
 html[data-dark-mode] .navcard-container .title {
 color: var(--text-default);
 }
 html[data-dark-mode] .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 html[data-dark-mode] .navcard-container:hover .card {
 box-shadow: 0 12px 28px -6px rgba(0, 0, 0, 0.45), 0 10px 12px -8px rgba(0, 0, 0, 0.40);
 }

 @media (prefers-color-scheme: dark) {
 html:not([data-dark-mode]) .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html:not([data-dark-mode]) .navcard-container .card-text {
 color: var(--gray-300);
 }
 html:not([data-dark-mode]) .navcard-container .title {
 color: var(--text-default);
 }
 html:not([data-dark-mode]) .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 }

&lt;/style&gt;



 
&lt;h2 id="heading"&gt;特性 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;✨ 自动为Markdown文件添加缺失的frontmatter字段（标题、日期、永久链接等）&lt;/li&gt;
&lt;li&gt;🔄 支持自定义frontmatter转换函数&lt;/li&gt;
&lt;li&gt;📁 支持自动生成基于文件路径的分类信息&lt;/li&gt;
&lt;li&gt;🗑️ 支持删除指定的frontmatter字段&lt;/li&gt;
&lt;li&gt;🌐 兼容VitePress的国际化配置&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-1"&gt;安装 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;安装 &lt;code&gt;vitepress-plugin-setfrontmatter&lt;/code&gt; 插件&lt;/p&gt;</description></item><item><title>License使用</title><link>https://xiaoying.org.cn/pages/6817ab/</link><pubDate>Fri, 28 Mar 2025 11:46:49 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6817ab/</guid><description>&lt;h2 id="heading"&gt;引用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="db864d0" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@RestController
@Slf4j
@RequestMapping(&amp;#34;/license&amp;#34;)
public class LicenseController {
 
 @Resource
 private LicenseService licenseService;

 @Resource
 private LicenseVerify licenseVerify;
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;获取服务器硬件信息 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b31eaeb" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Operation(summary = &amp;#34;获取服务器硬件信息&amp;#34;)
@GetMapping(&amp;#34;/getServerInfos&amp;#34;)
public BaseResponse&amp;lt;LicenseCheckModel&amp;gt; getServerInfos(@RequestParam String osName) {
 return licenseService.getServerInfos(osName);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;生成证书 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="94a467b" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Operation(summary = &amp;#34;生成证书&amp;#34;)
@PostMapping(&amp;#34;/generateLicense&amp;#34;)
public Map&amp;lt;String, Object&amp;gt; generateLicense(@RequestBody @Valid LicenseCreatorParam param) {
 return licenseService.generateLicense(param);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;上传授权文件 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="aa44fb1" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Operation(summary = &amp;#34;上传授权文件&amp;#34;)
@PostMapping(&amp;#34;/uploadLicense&amp;#34;)
public BaseResponse&amp;lt;String&amp;gt; uploadLicense(@RequestParam(&amp;#34;file&amp;#34;) MultipartFile file) throws Exception {
 return licenseService.uploadFileByParam(file);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;校验证书 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="44485af" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Operation(summary = &amp;#34;校验证书&amp;#34;)
@GetMapping(&amp;#34;/verifyLicense&amp;#34;)
public BaseResponse&amp;lt;Long&amp;gt; verifyLicense() throws Exception {
 return licenseVerify.verifyLicense();
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>wangEditor</title><link>https://xiaoying.org.cn/pages/4f7aaa/</link><pubDate>Thu, 27 Mar 2025 08:30:07 +0000</pubDate><guid>https://xiaoying.org.cn/pages/4f7aaa/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在线Marndown编辑器&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="29e8386" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
 import { WangEditor } from &amp;#34;liyao-vue-common&amp;#34;
 &amp;lt;/script&amp;gt;
 
 &amp;lt;template&amp;gt;
 &amp;lt;WangEditor /&amp;gt;
 &amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;可选参数 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="83c780f" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 定义 props
const props = defineProps({
 modelValue: {
 type: String,
 default: &amp;#39;&amp;#39;,
 },
 mode: {
 type: String,
 default: &amp;#39;default&amp;#39;,
 },
 readOnly: {
 type: Boolean,
 default: false,
 },
 toolbarConfig: {
 type: Object,
 default: () =&amp;gt; ({
 excludeKeys: [&amp;#39;fullScreen&amp;#39;],
 }),
 },
 uploadFileApi: Function,
 uploadVideoApi: Function,
})

// 定义 emits
const emit = defineEmits([&amp;#39;update:modelValue&amp;#39;])&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;更多配置请查看&lt;a href="https://www.wangeditor.com/v5/toolbar-config.html" rel="external" target="_blank"&gt;wangEditor官方文档&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>vitepress-plugin-link使用</title><link>https://xiaoying.org.cn/pages/53ad43/</link><pubDate>Tue, 25 Mar 2025 09:24:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/53ad43/</guid><description>&lt;h1 id="vitepress-plugin-link"&gt;vitepress-plugin-link &lt;a href="#vitepress-plugin-link" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="github"&gt;github地址 &lt;a href="#github" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



&lt;div class="row g-4 mb-3 mt-1 me-1 d-flex"&gt;
 
 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/vitepress-plugin-link" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/202503231752583.png" class="card-img-top mt-2" alt="vitepress-plugin-link" /&gt;
 
 &lt;span class="title mt-2"&gt;vitepress-plugin-link&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-primary position-absolute top-0 end-0"&gt;vitepress插件&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;这是一个适用于 vitepress的 Vite 插件，在vitepress启动后读取 markdown 文档 frontmatter的 url&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 

&lt;/div&gt;

&lt;style&gt;

 .navcard-container .card {
 background-color: #f6f6f7;
 transition: transform 0.3s ease, box-shadow 0.3s ease;
 border-radius: 10px;
 }

 .navcard-container:hover .card {
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
 transform: translateY(-3px);
 }

 .navcard-container .card-text {
 color: #67676c;
 font-size: 12px;
 overflow: hidden;
 white-space: normal;
 text-overflow: ellipsis;
 }

 .navcard-container .title {
 font-size: 14px;
 font-weight: 600;
 }

 .navcard-container .badge {
 margin: 5px 5px 0 0;
 border-radius: 14px;
 font-size: 9px;
 }

 .navcard-container .card-img-top {
 width: 40px;
 height: 40px;
 border-radius: 50%;
 margin: 0 10px;
 }

 
 html[data-dark-mode] .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html[data-dark-mode] .navcard-container .card-text {
 color: var(--gray-300);
 }
 html[data-dark-mode] .navcard-container .title {
 color: var(--text-default);
 }
 html[data-dark-mode] .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 html[data-dark-mode] .navcard-container:hover .card {
 box-shadow: 0 12px 28px -6px rgba(0, 0, 0, 0.45), 0 10px 12px -8px rgba(0, 0, 0, 0.40);
 }

 @media (prefers-color-scheme: dark) {
 html:not([data-dark-mode]) .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html:not([data-dark-mode]) .navcard-container .card-text {
 color: var(--gray-300);
 }
 html:not([data-dark-mode]) .navcard-container .title {
 color: var(--text-default);
 }
 html:not([data-dark-mode]) .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 }

&lt;/style&gt;



 
&lt;h2 id="heading"&gt;特性 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;🚀🚀 支持给 markdown 文档设置唯一的访问 &lt;strong&gt;永久链接&lt;/strong&gt;，不再因为 markdown 文档路径移动而导致访问地址发生变化&lt;/li&gt;
&lt;li&gt;🚀 读取 markdown 文档 &lt;code&gt;frontmatter&lt;/code&gt; 的 &lt;code&gt;url&lt;/code&gt;，挂载到 &lt;code&gt;themeConfig.urls&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;🚀 提供 &lt;code&gt;useurl&lt;/code&gt; hooks 函数拓展 &lt;code&gt;router&lt;/code&gt; 方法，支持 &lt;code&gt;router.push(href)&lt;/code&gt; 跳转到永久链接或实际的文件路径&lt;/li&gt;
&lt;li&gt;🚀 支持 locales 国际化，自动给 &lt;strong&gt;永久链接&lt;/strong&gt; 添加语言前缀，不同语言的永久链接不会重复&lt;/li&gt;
&lt;li&gt;🚀 支持 rewrite 路由重写，最终得到的文档路径是 rewrite 路由重写后的路径&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;永久链接&lt;/strong&gt; 支持导航栏激活高亮&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-1"&gt;安装 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;安装 &lt;code&gt;vitepress-plugin-link&lt;/code&gt; 插件&lt;/p&gt;</description></item><item><title>Hooks封装</title><link>https://xiaoying.org.cn/pages/086430/</link><pubDate>Mon, 24 Mar 2025 17:12:29 +0000</pubDate><guid>https://xiaoying.org.cn/pages/086430/</guid><description>&lt;h1 id="vue-3-hooks--npm-"&gt;Vue 3 Hooks 封装与 npm 使用指南 &lt;a href="#vue-3-hooks--npm-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="heading"&gt;一、概述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Vue 3 的 Composition API 提供了强大的逻辑复用能力，通过封装 Hooks，可以将组件的逻辑进行模块化封装，方便在多个组件中复用。本文将介绍如何封装 Vue 3 Hooks 并将其发布到 npm，以便其他开发者可以方便地下载和使用。&lt;/p&gt;
&lt;h2 id="-hooks"&gt;二、封装 Hooks &lt;a href="#-hooks" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;创建项目结构 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;1、创建项目文件夹，例如 &lt;code&gt;vue3-hooks&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;2、在项目文件夹中初始化 npm 项目：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="864dfed" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm init -y&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;3、安装 Vue 3 和其他必要的依赖：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="af15a9c" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install vue@3&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="-hooks-1"&gt;编写 Hooks &lt;a href="#-hooks-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;src&lt;/code&gt; 文件夹中创建一个 Hook 文件，例如 &lt;code&gt;useCounter.js&lt;/code&gt;：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6785132" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// src/useCounter.js
import { ref } from &amp;#39;vue&amp;#39;;

export function useCounter() {
 const count = ref(0);
 const increment = () =&amp;gt; {
 count.value&amp;#43;&amp;#43;;
 };
 const decrement = () =&amp;gt; {
 count.value--;
 };
 return {
 count,
 increment,
 decrement
 };
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;配置构建工具 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用 Vite 进行构建配置：&lt;/p&gt;</description></item><item><title>正则校验</title><link>https://xiaoying.org.cn/pages/d22904/</link><pubDate>Wed, 02 Jul 2025 19:59:46 +0000</pubDate><guid>https://xiaoying.org.cn/pages/d22904/</guid><description>&lt;h2 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;nav&gt;
	&lt;div class="nav nav-tabs" id="nav-tab" role="tablist"&gt;

		
		
		
		

		

		&lt;a class="nav-link active"
		 id="fcedabTab" data-bs-toggle="tab" data-bs-target="#fcedab"
		 type="button" role="tab" aria-controls="fcedab" aria-selected="true"&gt;npm&lt;/a&gt;

		

		&lt;a class="nav-link "
		 id="bafcedTab" data-bs-toggle="tab" data-bs-target="#bafced"
		 type="button" role="tab" aria-controls="bafced" aria-selected="true"&gt;yarn&lt;/a&gt;

		

		&lt;a class="nav-link "
		 id="cebdafTab" data-bs-toggle="tab" data-bs-target="#cebdaf"
		 type="button" role="tab" aria-controls="cebdaf" aria-selected="true"&gt;pnpm&lt;/a&gt;

		

	&lt;/div&gt;
&lt;/nav&gt;

&lt;div class="tab-content" id="nav-tab-content"&gt;

	







&lt;div class="tab-pane fade show active" id="fcedab" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="42ff59c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install regular-plus -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;







&lt;div class="tab-pane fade" id="bafced" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5d26a22" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add regular-plus -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;







&lt;div class="tab-pane fade" id="cebdaf" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="226e09b" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;pnpm add regular-plus -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;




&lt;/div&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;正则校验 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="aa4c745" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import regular from &amp;#39;regular-plus&amp;#39;;
 
console.log(regular.email.test(&amp;#39;someemail@gmail.com&amp;#39;)) // outputs true&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-3"&gt;可用校验 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b9dd50c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;email: RegExp; // 邮箱地址
url: RegExp; // URL地址
domain: RegExp; // 域名
ipv4: RegExp; // IPv4地址
creditCard: RegExp; // 信用卡号
slug: RegExp; // 全部由小写字母（a-z）、数字（0-9）、或 - 构成且不能有空格、下划线、大写字母、中文、特殊符号等
number: RegExp; // 正整数数字字符串
html: RegExp; // HTML标签匹配,
phone: RegExp; // 手机号码
sfzReg: RegExp; // 身份证号码
hexcolor: RegExp; // 十六进制颜色
date: RegExp; // 日期格式 YYYY-MM-DD
dateReg: RegExp; // 日期时间格式 YYYY-MM-DD HH:mm:ss
int: RegExp; // 整数
float: RegExp; // 浮点数
post: RegExp; // 邮政编码
qqReg: RegExp; // QQ号
wxReg: RegExp; // 微信号
carNoReg: RegExp; // 车牌号
password: RegExp; // 密码，至少8位，包含大小写字母和数字
fileExt: RegExp; // 文件拓展名的校验&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;自定义文件扩展名校验 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-5"&gt;默认可用类型 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="43efbc8" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;type FileType = &amp;#39;image&amp;#39; | &amp;#39;doc&amp;#39; | &amp;#39;archive&amp;#39;;
const fileTypeExtMap: Record&amp;lt;FileType, string[]&amp;gt; = {
 image: [&amp;#39;jpg&amp;#39;, &amp;#39;jpeg&amp;#39;, &amp;#39;png&amp;#39;, &amp;#39;gif&amp;#39;, &amp;#39;bmp&amp;#39;, &amp;#39;webp&amp;#39;, &amp;#39;svg&amp;#39;],
 doc: [&amp;#39;pdf&amp;#39;, &amp;#39;doc&amp;#39;, &amp;#39;docx&amp;#39;, &amp;#39;xls&amp;#39;, &amp;#39;xlsx&amp;#39;, &amp;#39;ppt&amp;#39;, &amp;#39;pptx&amp;#39;, &amp;#39;txt&amp;#39;, &amp;#39;md&amp;#39;],
 archive: [&amp;#39;zip&amp;#39;, &amp;#39;rar&amp;#39;],
};&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="-filetype"&gt;扩展 FileType &lt;a href="#-filetype" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可以通过 TypeScript 的联合类型扩展 FileType&lt;/p&gt;</description></item><item><title>Excel导入导出</title><link>https://xiaoying.org.cn/pages/d0ea9e/</link><pubDate>Fri, 28 Mar 2025 11:47:47 +0000</pubDate><guid>https://xiaoying.org.cn/pages/d0ea9e/</guid><description>&lt;h2 id="heading"&gt;引用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ba699a4" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@RestController
@RequestMapping(&amp;#34;/excel&amp;#34;)
public class ExcelController {
 ...
 @Resource
 private ExcelService excelService;
 ...
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="excel"&gt;Excel导入 &lt;a href="#excel" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;基本导入 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d22dd69" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/upload&amp;#34;)
@Operation(summary = &amp;#34;excel导入&amp;#34;)
@ResponseBody
public List&amp;lt;Excel&amp;gt; upload(@RequestExcel List&amp;lt;Excel&amp;gt; dataList) {

 // 数据校验
 if (dataList == null || dataList.isEmpty()) {
 throw new BusinessException(ErrorCode.PARAMS_ERROR, &amp;#34;上传数据为空&amp;#34;);
 }

 // 批量保存到数据库
 boolean result = excelService.saveBatch(dataList);
 if (!result) {
 throw new BusinessException(ErrorCode.OPERATION_ERROR);
 }

 return dataList;
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;忽略部分字段 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;导入的字段会按给定的实体类顺序来，所以当某个字段不需要导入时必须用&lt;code&gt;@ExcelIgnore&lt;/code&gt;，使得导入的Excel表字段的顺序与实体类一致&lt;/p&gt;</description></item><item><title>monacoEditor</title><link>https://xiaoying.org.cn/pages/ad2a8f/</link><pubDate>Thu, 27 Mar 2025 08:30:07 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ad2a8f/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在线代码编辑器&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ab140f5" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
 import { MonacoEditor } from &amp;#34;liyao-vue-common&amp;#34;
 &amp;lt;/script&amp;gt;
 
 &amp;lt;template&amp;gt;
 &amp;lt;MonacoEditor /&amp;gt;
 &amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;可选参数 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8408987" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;export const editorProps = {
 width: {
 type: [String, Number] as PropType&amp;lt;string | number&amp;gt;,
 default: &amp;#39;100%&amp;#39;
 },
 height: {
 type: [String, Number] as PropType&amp;lt;string | number&amp;gt;,
 default: &amp;#39;500px&amp;#39;
 },
 theme: {
 type: String as PropType&amp;lt;Theme&amp;gt;,
 validator(value: string): boolean {
 return [&amp;#39;vs&amp;#39;, &amp;#39;hc-black&amp;#39;, &amp;#39;vs-dark&amp;#39;].includes(value)
 },
 default: &amp;#39;vs-dark&amp;#39;
 },
 options: {
 type: Object as PropType&amp;lt;Partial&amp;lt;Options&amp;gt;&amp;gt;,
 default() {
 return {
 automaticLayout: true,
 foldingStrategy: &amp;#39;indentation&amp;#39;,
 renderLineHighlight: &amp;#39;all&amp;#39;,
 selectOnLineNumbers: true,
 minimap: {
 enabled: false
 },
 readOnly: false,
 contextmenu: true,
 fontSize: 16,
 scrollBeyondLastLine: false,
 overviewRulerBorder: false
 }
 }
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;更多配置请查看&lt;a href="https://microsoft.github.io/monaco-editor/docs.html" rel="external" target="_blank"&gt;MonacoEditor官方文档&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>自动生成侧边栏</title><link>https://xiaoying.org.cn/pages/6d8b82/</link><pubDate>Tue, 25 Mar 2025 09:26:56 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6d8b82/</guid><description>&lt;h1 id="vitepress-plugin-sidebar-depth"&gt;vitepress-plugin-sidebar-depth使用 &lt;a href="#vitepress-plugin-sidebar-depth" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="github"&gt;github地址 &lt;a href="#github" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



&lt;div class="row g-4 mb-3 mt-1 me-1 d-flex"&gt;
 
 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/vitepress-plugin-sidebar-depth" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/202503231752583.png" class="card-img-top mt-2" alt="vitepress-plugin-sidebar-depth" /&gt;
 
 &lt;span class="title mt-2"&gt;vitepress-plugin-sidebar-depth&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-primary position-absolute top-0 end-0"&gt;vitepress插件&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;这是一个适用于vitepress的 Vite 插件，在vitepress启动后扫描 markdown 文档来自动生成侧边栏&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 

&lt;/div&gt;

&lt;style&gt;

 .navcard-container .card {
 background-color: #f6f6f7;
 transition: transform 0.3s ease, box-shadow 0.3s ease;
 border-radius: 10px;
 }

 .navcard-container:hover .card {
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
 transform: translateY(-3px);
 }

 .navcard-container .card-text {
 color: #67676c;
 font-size: 12px;
 overflow: hidden;
 white-space: normal;
 text-overflow: ellipsis;
 }

 .navcard-container .title {
 font-size: 14px;
 font-weight: 600;
 }

 .navcard-container .badge {
 margin: 5px 5px 0 0;
 border-radius: 14px;
 font-size: 9px;
 }

 .navcard-container .card-img-top {
 width: 40px;
 height: 40px;
 border-radius: 50%;
 margin: 0 10px;
 }

 
 html[data-dark-mode] .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html[data-dark-mode] .navcard-container .card-text {
 color: var(--gray-300);
 }
 html[data-dark-mode] .navcard-container .title {
 color: var(--text-default);
 }
 html[data-dark-mode] .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 html[data-dark-mode] .navcard-container:hover .card {
 box-shadow: 0 12px 28px -6px rgba(0, 0, 0, 0.45), 0 10px 12px -8px rgba(0, 0, 0, 0.40);
 }

 @media (prefers-color-scheme: dark) {
 html:not([data-dark-mode]) .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html:not([data-dark-mode]) .navcard-container .card-text {
 color: var(--gray-300);
 }
 html:not([data-dark-mode]) .navcard-container .title {
 color: var(--text-default);
 }
 html:not([data-dark-mode]) .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 }

&lt;/style&gt;



 
&lt;h2 id="heading"&gt;特性 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;🚀 扫描项目的目录，自动生成侧边栏数据，挂载到 &lt;code&gt;themeConfig.sidebar&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;🚀 支持自定义扫描的递归深度&lt;/li&gt;
&lt;li&gt;🚀 支持 &lt;code&gt;01.guide.md&lt;/code&gt; 带有序号的文件格式，在渲染侧边栏数据时，带序号的文件位置比不带序号的文件高&lt;/li&gt;
&lt;li&gt;🚀 支持 locales 国际化，挂载到 &lt;code&gt;locales.[lang].themeConfig.sidebar&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;blockquote&gt;
 &lt;p&gt;说明：在同层目录下，如果存在相同序号的文件时，后面的文件会覆盖前面的文件&lt;/p&gt;</description></item><item><title>nginx常用配置</title><link>https://xiaoying.org.cn/pages/d0b138/</link><pubDate>Wed, 02 Jul 2025 20:40:06 +0000</pubDate><guid>https://xiaoying.org.cn/pages/d0b138/</guid><description>&lt;h2 id="https"&gt;配置HTTPS &lt;a href="#https" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0e1379e" class="language-nginx wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;server {
 listen 443 ssl;
 server_name xiaoying.org.cn;
 root /usr/local/dist; #前端打包文件位置

 #域名证书文件名称
 ssl_certificate /etc/nginx/fullchain.cer;
 #域名证书私钥文件名称
 ssl_certificate_key /etc/nginx/xiaoying.org.cn.key;
 
 #请按照以下协议配置
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
 #请按照以下套件配置，配置加密套件，写法遵循 openssl 标准。
 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
 ssl_prefer_server_ciphers on;
 ssl_session_cache shared:SSL:1m;
 ssl_session_timeout 10m;

 location ^~ /api/ { #后端接口前缀
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_pass http://127.0.0.1:8080; #后端接口地址
 }

 include /etc/nginx/default.d/*.conf;

 error_page 404 /404.html;
 location = /40x.html {
 }

 error_page 500 502 503 504 /50x.html;
 location = /50x.html {
 }
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="gzip"&gt;开启gzip压缩静态文件 &lt;a href="#gzip" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-gzip-"&gt;配置 GZip 压缩 &lt;a href="#-gzip-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;gzip 可以在 http, server, location 中和配置，这里配置到 http 下是全局配置，&lt;/p&gt;</description></item><item><title>重写文章路由</title><link>https://xiaoying.org.cn/pages/47a27c/</link><pubDate>Sat, 31 May 2025 00:40:58 +0000</pubDate><guid>https://xiaoying.org.cn/pages/47a27c/</guid><description>&lt;h1 id="vitepress-plugin-sidebar-url"&gt;vitepress-plugin-sidebar-url &lt;a href="#vitepress-plugin-sidebar-url" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;VitePress 插件：自动生成 sidebar 侧边栏和 url rewrites 映射，支持数字前缀排序、collapsed 配置、url 匹配高亮、目录/文件名美化等。&lt;/p&gt;
&lt;h2 id="github"&gt;github地址 &lt;a href="#github" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



&lt;div class="row g-4 mb-3 mt-1 me-1 d-flex"&gt;
 
 
 
 
 
 
 
 
 
 
 
 &lt;a href="https://github.com/liyao52033/vitepress-plugin-sidebar-url" target="_blank" class="col-md-6 navcard-container d-block text-decoration-none"&gt;
 &lt;div class="card h-100 d-flex flex-column transition-all duration-300 hover:shadow-lg hover:-translate-y-1"&gt;
 &lt;div class="relative"&gt;
 &lt;div class="d-flex align-items-center"&gt;
 
 &lt;img src="https://img.xiaoying.org.cn/img/202503231752583.png" class="card-img-top mt-2" alt="vitepress-plugin-sidebar-url" /&gt;
 
 &lt;span class="title mt-2"&gt;vitepress-plugin-sidebar-url&lt;/span&gt;
 &lt;/div&gt;
 
 &lt;span class="badge bg-primary position-absolute top-0 end-0"&gt;vitepress插件&lt;/span&gt;
 
 &lt;/div&gt;
 &lt;div class="card-body"&gt;
 &lt;p class="card-text mt-1 ms-1"&gt;这是一个适用于vitepress的 Vite 插件，vitepress启动时，插件会重写路由用url作为链接并生成侧边栏&lt;/p&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;/a&gt;
 

&lt;/div&gt;

&lt;style&gt;

 .navcard-container .card {
 background-color: #f6f6f7;
 transition: transform 0.3s ease, box-shadow 0.3s ease;
 border-radius: 10px;
 }

 .navcard-container:hover .card {
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
 transform: translateY(-3px);
 }

 .navcard-container .card-text {
 color: #67676c;
 font-size: 12px;
 overflow: hidden;
 white-space: normal;
 text-overflow: ellipsis;
 }

 .navcard-container .title {
 font-size: 14px;
 font-weight: 600;
 }

 .navcard-container .badge {
 margin: 5px 5px 0 0;
 border-radius: 14px;
 font-size: 9px;
 }

 .navcard-container .card-img-top {
 width: 40px;
 height: 40px;
 border-radius: 50%;
 margin: 0 10px;
 }

 
 html[data-dark-mode] .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html[data-dark-mode] .navcard-container .card-text {
 color: var(--gray-300);
 }
 html[data-dark-mode] .navcard-container .title {
 color: var(--text-default);
 }
 html[data-dark-mode] .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 html[data-dark-mode] .navcard-container:hover .card {
 box-shadow: 0 12px 28px -6px rgba(0, 0, 0, 0.45), 0 10px 12px -8px rgba(0, 0, 0, 0.40);
 }

 @media (prefers-color-scheme: dark) {
 html:not([data-dark-mode]) .navcard-container .card {
 background-color: var(--gray-800);
 border: 1px solid var(--gray-700);
 box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.35), 0 8px 10px -6px rgba(0, 0, 0, 0.32);
 }
 html:not([data-dark-mode]) .navcard-container .card-text {
 color: var(--gray-300);
 }
 html:not([data-dark-mode]) .navcard-container .title {
 color: var(--text-default);
 }
 html:not([data-dark-mode]) .navcard-container .badge {
 background-color: var(--gray-900);
 color: var(--gray-300);
 border: 1px solid var(--gray-700);
 }
 }

&lt;/style&gt;



 
&lt;h2 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;nav&gt;
	&lt;div class="nav nav-tabs" id="nav-tab" role="tablist"&gt;

		
		
		
		

		

		&lt;a class="nav-link active"
		 id="bdfaceTab" data-bs-toggle="tab" data-bs-target="#bdface"
		 type="button" role="tab" aria-controls="bdface" aria-selected="true"&gt;npm&lt;/a&gt;

		

		&lt;a class="nav-link "
		 id="dabfceTab" data-bs-toggle="tab" data-bs-target="#dabfce"
		 type="button" role="tab" aria-controls="dabfce" aria-selected="true"&gt;🛠️ Options&lt;/a&gt;

		

		&lt;a class="nav-link "
		 id="deabfcTab" data-bs-toggle="tab" data-bs-target="#deabfc"
		 type="button" role="tab" aria-controls="deabfc" aria-selected="true"&gt;pnpm&lt;/a&gt;

		

	&lt;/div&gt;
&lt;/nav&gt;

&lt;div class="tab-content" id="nav-tab-content"&gt;

	







&lt;div class="tab-pane fade show active" id="bdface" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4b92782" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install vitepress-plugin-sidebar-url -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;







&lt;div class="tab-pane fade" id="dabfce" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e98df88" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add vitepress-plugin-sidebar-url -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;







&lt;div class="tab-pane fade" id="deabfc" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="f5d5763" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;pnpm i vitepress-plugin-sidebar-url -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;




&lt;/div&gt;
&lt;h2 id="heading-1"&gt;用法 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;配置 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;nav&gt;
	&lt;div class="nav nav-tabs" id="nav-tab" role="tablist"&gt;

		
		
		
		

		

		&lt;a class="nav-link active"
		 id="fdacebTab" data-bs-toggle="tab" data-bs-target="#fdaceb"
		 type="button" role="tab" aria-controls="fdaceb" aria-selected="true"&gt;.vitepress/config.ts&lt;/a&gt;

		

		&lt;a class="nav-link "
		 id="ecdfabTab" data-bs-toggle="tab" data-bs-target="#ecdfab"
		 type="button" role="tab" aria-controls="ecdfab" aria-selected="true"&gt;typescript&lt;/a&gt;

		

	&lt;/div&gt;
&lt;/nav&gt;

&lt;div class="tab-content" id="nav-tab-content"&gt;

	







&lt;div class="tab-pane fade show active" id="fdaceb" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="22cc3c6" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { defineConfig } from &amp;#39;vitepress&amp;#39;
import SidebarurlPlugin, { generatedSidebar, generatedRewrites } from &amp;#39;vitepress-plugin-sidebar-url&amp;#39;
// import rewritesJson from &amp;#39;../rewrites.json&amp;#39;

export default defineConfig({
 vite: {
 plugins: [
 SidebarurlPlugin({
 root: &amp;#39;docs&amp;#39;, //根目录
 dir: &amp;#39;docs/articles&amp;#39;, //Markdown文章目录路径
 rewritesPath: &amp;#39;docs/rewrites.json&amp;#39;, //重写规则文件路径
 // rewrites: rewritesJson.rewrites, //直接提供的重写规则，启动时注释这个，生成json后再写，后续优先使用这个本地的json
 options: { collapsed: true }, //侧边栏是否折叠
 ignoreDirs: { //忽略目录
 rewriteIgnores: [], 
 sidebarIgnores: [] 
 },
 navLinks: [ //导航栏
 { text: &amp;#39;组件&amp;#39;, link: &amp;#39;/pages/fe4521&amp;#39; },
 { text: &amp;#39;后端&amp;#39;, link: &amp;#39;/pages/571de5&amp;#39; },
 { text: &amp;#39;资源&amp;#39;, link: &amp;#39;/pages/87a36a&amp;#39; }
 ],
 })
 ]
 },
 // 使用插件自动生成的侧边栏和重写规则
 rewrites: generatedRewrites, 
 themeConfig: {
 sidebar: generatedSidebar
 }
})&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;







&lt;div class="tab-pane fade" id="ecdfab" role="tabpanel" aria-labelledby="nav-1"&gt;

	


















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d8a3924" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;export interface SidebarurlOptions {
 /**
 * 根目录, 默认为 &amp;#39;docs&amp;#39;
 */
 root?: string; 
 /**
 * Markdown文章目录路径，默认为 &amp;#39;docs/articles&amp;#39;
 */
 dir?: string; 
 /**
 * 重写规则文件路径，默认为 &amp;#39;docs/rewrites.json&amp;#39;
 */
 rewritesPath?: string; 
 /**
 * 直接提供的重写规则，一般为rewritesJson.rewrites，rewritesJson为生成的json文件
 *
 */
 rewrites?: Record&amp;lt;string, string&amp;gt;, 
 /**
 * sidebar配置，是否折叠
 */
 options?: { collapsed: boolean }, 
 /**
 * 导航栏
 */
 navLinks?: { text: string, link?: string, items?: any[] }[] | null | undefined, 
 /**
 * 忽略的侧边栏目录列表
 *
 * */
 ignoreDirs?: IgnoreDirs; 
}


export interface IgnoreDirs {
 /**
 * 重写规则默认忽略目录为 [&amp;#34;.vitepress&amp;#34;, &amp;#34;node_modules&amp;#34;, &amp;#34;public&amp;#34;, &amp;#34;dist&amp;#34;] 
 */
 rewriteIgnores: string[];
 /**
 * 侧边栏默认忽略目录为 [&amp;#34;.vitepress&amp;#34;, &amp;#34;node_modules&amp;#34;, &amp;#34;public&amp;#34;, &amp;#34;dist&amp;#34;, &amp;#34;@pages&amp;#34;, &amp;#34;index.md&amp;#34;] 
 */
 sidebarIgnores: string[];
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;


&lt;/div&gt;



&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;插件会在启动时生成侧边栏和重写规则，优先从&lt;code&gt;rewrites&lt;/code&gt;参数获取重写规则，其次从生成的json文件读取，建议生成json文件后配置该参数&lt;/p&gt;</description></item><item><title>CopyButton</title><link>https://xiaoying.org.cn/pages/04abfc/</link><pubDate>Fri, 04 Apr 2025 03:25:42 +0000</pubDate><guid>https://xiaoying.org.cn/pages/04abfc/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;复制组件，点击即可复制对应的内容&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="594ac43" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;copy-button :text=&amp;#34;InputText&amp;#34;&amp;gt;&amp;lt;/copy-button&amp;gt;
 &amp;lt;el-input v-model=&amp;#34;InputText&amp;#34; /&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import CopyButton from &amp;#39;liyao-vue-common&amp;#39;;

const InputText = ref(&amp;#39;&amp;#39;);
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>数据脱敏</title><link>https://xiaoying.org.cn/pages/c54241/</link><pubDate>Fri, 28 Mar 2025 13:10:11 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c54241/</guid><description>&lt;h2 id="heading"&gt;添加注解脱敏 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在字段上加上&lt;code&gt;@Desensitization&lt;/code&gt;注解及对应的类型即可脱敏&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3a9832f" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Data
public class Person {
 @Desensitization(type = DesensitizationTypeEnum.PHONE)
 private String phone;

 @Desensitization(type = DesensitizationTypeEnum.MY_RULE, startInclude = 3, endExclude = 7)
 private String customPhone;

 @Desensitization(type = DesensitizationTypeEnum.EMAIL)
 private String email;
 
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;所有类型如下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="40496f0" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;MY_RULE //可自定义脱敏的位置
USER_ID //用户id
CHINESE_NAME //中文姓名
ID_CARD // 身份证号
FIXED_PHONE //座机号码
PHONE //手机号码
ADDRESS //地址
EMAIL //电子邮件
PASSWORD //密码
CAR_LICENSE //中国大陆车牌，包含普通车辆、新能源车辆
BANK_CARD //银行卡号&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="69010b2" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@PostMapping(&amp;#34;/&amp;#34;)
public Person testDesensitization(){
 Person person = new Person();
 person.setPhone(&amp;#34;12345678901&amp;#34;);
 person.setCustomPhone(&amp;#34;12345678901&amp;#34;);
 person.setEmail(&amp;#34;12345678901@qq.com&amp;#34;);
 System.out.println(person);
 return person;
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>集成Coze国际版</title><link>https://xiaoying.org.cn/pages/d779c2/</link><pubDate>Sun, 10 Aug 2025 23:10:46 +0000</pubDate><guid>https://xiaoying.org.cn/pages/d779c2/</guid><description>&lt;h2 id="heading"&gt;创建智能体 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;访问&lt;a href="https://www.coze.com/home" rel="external" target="_blank"&gt;扣子主页&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 填写自己的智能体信息，这里可以自定义，想填写什么就填写什么就行。











 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20250810143401463.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20250810143401463.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20250810143401463.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20250810143401463.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20250810143401463.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20250810143401463.png?w=2400 2400w
 " sizes="100vw" alt="image-20250810143401123" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="heading-1"&gt;编排智能体 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建好了之后就需要去编排这个智能体，我仅仅填写了一小部分的人设与回复逻辑，然后就让 AI 润色了一下，设置技能，例如开场白和预置问题。











 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20250810142925779.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20250810142925779.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20250810142925779.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20250810142925779.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20250810142925779.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20250810142925779.png?w=2400 2400w
 " sizes="100vw" alt="image-20250810142925562" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>防重提交</title><link>https://xiaoying.org.cn/pages/1eec9f/</link><pubDate>Sat, 05 Apr 2025 09:57:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/1eec9f/</guid><description>&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;为防止用户在短时间内多次提交相同请求，系统提供了防重复提交功能。通过简单的注解配置，即可实现此功能。&lt;/div&gt;
 

&lt;/div&gt;

&lt;h2 id="heading"&gt;&lt;a href="https://www.youlai.tech/youlai-boot/3.%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/4.%E9%98%B2%E9%87%8D%E6%8F%90%E4%BA%A4.html#%E4%BD%BF%E7%94%A8%E9%98%B2%E9%87%8D%E6%8F%90%E4%BA%A4" rel="external" target="_blank"&gt;使用防重提交&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在需要防重复提交的接口上添加 &lt;code&gt;@RepeatSubmit&lt;/code&gt; 注解即可。通过注解参数 &lt;code&gt;expire&lt;/code&gt;，可以灵活控制重复提交的时间间隔（单位：秒）。如果不设置，默认时间为 5 秒。&lt;/p&gt;</description></item><item><title>uploadCos使用</title><link>https://xiaoying.org.cn/pages/222118/</link><pubDate>Tue, 25 Mar 2025 08:27:21 +0000</pubDate><guid>https://xiaoying.org.cn/pages/222118/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;拖拽式文件上传组件，主要用于图片上传到对象存储服务（如COS、OSS等）。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;参数 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;属性名&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;必填&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;uploadFileApi&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Function&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;-&lt;/td&gt;
 &lt;td&gt;上传文件的API函数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;modelValue&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;&amp;quot;&amp;quot;&lt;/td&gt;
 &lt;td&gt;图片URL，支持v-model双向绑定&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;maxFileSize&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Number&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;单个文件上传大小限制（单位：MB）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;accept&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;&amp;ldquo;*&amp;rdquo;&lt;/td&gt;
 &lt;td&gt;允许上传的文件类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;dataPath&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;Array&amp;lt;String&amp;gt;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;['data']&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;数据在响应中的路径，如&lt;code&gt;['result','url']&lt;/code&gt;表示取&lt;code&gt;response.result.url&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-2"&gt;插槽 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;插槽名&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;default&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;默认插槽，可自定义拖拽区域内容&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;tip &lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;提示信息插槽，显示在上传区域下方&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-3"&gt;使用示例 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-4"&gt;基本使用 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="02ff633" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;upload-cos v-model=&amp;#34;imageUrl&amp;#34; :uploadFileApi=&amp;#34;uploadToServer&amp;#34; xmlns=&amp;#34;&amp;#34;&amp;gt;&amp;lt;/upload-cos&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-5"&gt;带参数使用 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2a86b6d" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 带参数使用示例 --&amp;gt;
&amp;lt;template&amp;gt;
 &amp;lt;upload-cos
 v-model=&amp;#34;imageUrl&amp;#34;
 :uploadFileApi=&amp;#34;uploadToServer&amp;#34;
 :maxFileSize=&amp;#34;5&amp;#34;
 accept=&amp;#34;image/png, image/jpeg&amp;#34;
 :dataPath=&amp;#34;[&amp;#39;result&amp;#39;, &amp;#39;path&amp;#39;]&amp;#34;
 &amp;gt;&amp;lt;/upload-cos&amp;gt; &amp;lt;!-- 确保闭合标签 --&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-6"&gt;使用插槽自定义内容 &lt;a href="#heading-6" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="936c6a5" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;upload-cos :uploadFileApi=&amp;#34;uploadToServer&amp;#34;&amp;gt;
 &amp;lt;!-- 自定义上传区域 --&amp;gt;
 &amp;lt;template #default&amp;gt;
 &amp;lt;div class=&amp;#34;custom-upload-area&amp;#34;&amp;gt;
 &amp;lt;i class=&amp;#34;el-icon-upload&amp;#34;&amp;gt;&amp;lt;/i&amp;gt;
 &amp;lt;div&amp;gt;点击或拖拽图片到此区域上传&amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
 
 &amp;lt;!-- 自定义提示信息 --&amp;gt;
 &amp;lt;template #tip&amp;gt;
 &amp;lt;div class=&amp;#34;custom-tip&amp;#34;&amp;gt;支持jpg、png格式，文件小于5MB&amp;lt;/div&amp;gt;
 &amp;lt;/template&amp;gt;
 &amp;lt;/upload-cos&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
// 上传函数示例
function uploadToServer(file: File) {
 const formData = new FormData();
 formData.append(&amp;#34;file&amp;#34;, file);
 formData.append(&amp;#34;biz&amp;#34;, &amp;#34;user_avatar&amp;#34;);
 return request({
 url: &amp;#34;/api/cos/upload&amp;#34;,
 method: &amp;#34;post&amp;#34;,
 data: formData,
 headers: {
 &amp;#34;Content-Type&amp;#34;: &amp;#34;multipart/form-data&amp;#34;,
 },
 });
 }
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>管理API响应和错误处理</title><link>https://xiaoying.org.cn/pages/748a67/</link><pubDate>Tue, 15 Apr 2025 20:00:07 +0000</pubDate><guid>https://xiaoying.org.cn/pages/748a67/</guid><description>&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这是一个基于Spring Boot 的轻量级工具包，用于统一处理应用程序中的错误码、异常和响应格式。该starter提供了一套完整的异常处理机制，帮助开发者更加规范和高效地管理API响应和错误处理。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;功能特点 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;统一错误码管理&lt;/strong&gt;：预定义常用错误码，支持自定义扩展&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自定义业务异常&lt;/strong&gt;：提供BusinessException类，支持错误码和自定义错误信息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;异常抛出工具类&lt;/strong&gt;：ThrowUtils工具类简化异常抛出操作&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局异常处理&lt;/strong&gt;：自动捕获并处理各类异常，转换为统一的响应格式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;响应结果封装&lt;/strong&gt;：统一API响应格式，提供成功和失败响应的快捷方法&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数校验异常处理&lt;/strong&gt;：自动处理参数校验失败的情况&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;自动配置&lt;/strong&gt;：支持Spring Boot自动配置，零配置即可使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;安装方法 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;&lt;p&gt;依赖可能非最新版本，请前往maven获取最新版本&lt;/p&gt;
&lt;p&gt;&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/ErrorCode-spring-boot-starter" rel="external" target="_blank"&gt;Spring Boot 2&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;地址&lt;/p&gt;</description></item><item><title>uploadLocal使用</title><link>https://xiaoying.org.cn/pages/15e870/</link><pubDate>Tue, 25 Mar 2025 07:59:00 +0000</pubDate><guid>https://xiaoying.org.cn/pages/15e870/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;按钮式文件上传组件&lt;/p&gt;
&lt;h2 id="heading-1"&gt;参数 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;属性名&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;必填&lt;/th&gt;
 &lt;th&gt;默认值&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;importFile&lt;/td&gt;
 &lt;td&gt;Function&lt;/td&gt;
 &lt;td&gt;是&lt;/td&gt;
 &lt;td&gt;-&lt;/td&gt;
 &lt;td&gt;导入文件处理函数，接收文件对象作为参数&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;allowedExtensions&lt;/td&gt;
 &lt;td&gt;Array&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;[]&lt;/td&gt;
 &lt;td&gt;允许的文件扩展名，如 [&amp;rsquo;.xlsx&amp;rsquo;, &amp;lsquo;.xls&amp;rsquo;, &amp;lsquo;.csv&amp;rsquo;]&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;maxFileSize&lt;/td&gt;
 &lt;td&gt;Number&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;单个文件上传大小限制（单位：MB）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;acceptType&lt;/td&gt;
 &lt;td&gt;String&lt;/td&gt;
 &lt;td&gt;否&lt;/td&gt;
 &lt;td&gt;&amp;ldquo;*&amp;rdquo;&lt;/td&gt;
 &lt;td&gt;允许上传的文件类型&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-2"&gt;插槽 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;插槽名&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;default&lt;/td&gt;
 &lt;td&gt;默认插槽，用于自定义上传按钮文本&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;trigger&lt;/td&gt;
 &lt;td&gt;触发按钮插槽，可完全自定义上传按钮&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-3"&gt;使用示例 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-4"&gt;基本使用 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e531a45" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;uploadLocal :importFile=&amp;#34;handleImportFile&amp;#34;&amp;gt;
 导入Excel
 &amp;lt;/uploadLocal&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-5"&gt;带参数使用 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="f40f55c" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;uploadLocal 
 :importFile=&amp;#34;handleImportFile&amp;#34;
 :allowedExtensions=&amp;#34;[&amp;#39;.xlsx&amp;#39;, &amp;#39;.xls&amp;#39;, &amp;#39;.csv&amp;#39;]&amp;#34;
 :maxFileSize=&amp;#34;20&amp;#34;
 acceptType=&amp;#34;.xlsx,.xls,.csv&amp;#34;
&amp;gt;
 导入
&amp;lt;/uploadLocal&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-6"&gt;使用插槽自定义内容 &lt;a href="#heading-6" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cee14b9" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;uploadLocal :importFile=&amp;#34;handleImportFile&amp;#34;&amp;gt;
 &amp;lt;!-- 自定义按钮文本 --&amp;gt;
 点击导入数据文件
 &amp;lt;/uploadLocal&amp;gt;
 
 &amp;lt;!-- 完全自定义按钮 --&amp;gt;
 &amp;lt;uploadLocal :importFile=&amp;#34;handleImportFile&amp;#34;&amp;gt;
 &amp;lt;template #trigger&amp;gt;
 &amp;lt;el-button type=&amp;#34;success&amp;#34; icon=&amp;#34;el-icon-upload&amp;#34;&amp;gt;
 导入数据
 &amp;lt;/el-button&amp;gt;
 &amp;lt;/template&amp;gt;
 &amp;lt;/uploadLocal&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
// 处理导入Excel文件
const handleImportFile = (file) =&amp;gt; {
 console.log(&amp;#39;处理导入的文件:&amp;#39;, file.name)
 // 实际项目中在这里处理Excel文件
 console.log(&amp;#39;文件大小:&amp;#39;, (file.size / 1024 / 1024).toFixed(2) &amp;#43; &amp;#39;MB&amp;#39;)
 console.log(&amp;#39;文件类型:&amp;#39;, file.type)
}
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="uploadlocaluploadcosui"&gt;使用uploadLocal实现uploadCos的UI &lt;a href="#uploadlocaluploadcosui" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;可以通过利用uploadLocal组件的插槽功能，实现与uploadCos相似的UI效果：&lt;/p&gt;</description></item><item><title>配置meilisearch</title><link>https://xiaoying.org.cn/pages/09b133/</link><pubDate>Sat, 06 Sep 2025 16:44:03 +0000</pubDate><guid>https://xiaoying.org.cn/pages/09b133/</guid><description>&lt;h2 id="_1"&gt;_1、服务端配置 &lt;a href="#_1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="_11"&gt;_1.1、部署 &lt;a href="#_11" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;官方对于部署的介绍非常详细，各种方案都提供了，我这里选择使用 docker 来进行部署。&lt;/p&gt;
&lt;p&gt;添加服务启动脚本&lt;code&gt;start.sh&lt;/code&gt;到&lt;code&gt;/tmp/scraper&lt;/code&gt;目录&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8c3505c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;docker run -itd --name meilisearch -p 7700:7700 --restart=always \
 -e MEILI_ENV=&amp;#34;production&amp;#34; -e MEILI_NO_ANALYTICS=true \
 -e MEILI_MASTER_KEY=&amp;#34;自定义一个不少于16字节的秘钥&amp;#34; \
 -v $(pwd)/meili_data:/meili_data \
 getmeili/meilisearch&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;自建的时候，需要将环境变量声明为生产，并且必须指定 master-key，否则将会提示无法使用。&lt;/p&gt;
&lt;p&gt;然后运行该脚本，服务启动，通过监听日志，查看服务状态是否正常。&lt;/p&gt;
&lt;p&gt;也可以请求服务的健康接口进行验证：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b173fed" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;$ curl -s http://localhost:7700/health | jq
{
 &amp;#34;status&amp;#34;: &amp;#34;available&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;注意，生产模式下，只有这一个接口是不需要秘钥认证即可访问的，其他接口访问的时候都需要带上秘钥。&lt;/p&gt;
&lt;h3 id="_12key"&gt;_1.2、创建搜索的key &lt;a href="#_12key" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;上边有了一个 master-key 用于爬虫抓取使用，还需要创建一个只有搜索权限的 key，可通过如下命令进行创建&lt;code&gt;search.sh&lt;/code&gt;到
&lt;code&gt;/tmp/scraper&lt;/code&gt;目录&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="bb452ab" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;curl \
 -X POST &amp;#39;http://localhost:7700/keys&amp;#39; \
 -H &amp;#39;Content-Type: application/json&amp;#39; \
 -H &amp;#39;Authorization: Bearer 你自定义的秘钥&amp;#39; \
 --data-binary &amp;#39;{
 &amp;#34;description&amp;#34;: &amp;#34;vp.xiaoying.org.cn key&amp;#34;,
 &amp;#34;actions&amp;#34;: [&amp;#34;search&amp;#34;],
 &amp;#34;indexes&amp;#34;: [&amp;#34;blog&amp;#34;], // 第四步建立索引抓取配置中的index_uid的值需与该值保持一致
 &amp;#34;expiresAt&amp;#34;: &amp;#34;2099-01-01T00:00:00Z&amp;#34;
 }&amp;#39;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;创建完成之后，能看到返回内容中有一个 key 的字段，就是这个只有搜索权限的 key 了。&lt;/p&gt;</description></item><item><title>认证模块</title><link>https://xiaoying.org.cn/pages/24f3f7/</link><pubDate>Sat, 26 Apr 2025 11:01:09 +0000</pubDate><guid>https://xiaoying.org.cn/pages/24f3f7/</guid><description>&lt;h1 id="spring-boot-3-"&gt;Spring Boot 3 认证模块 &lt;a href="#spring-boot-3-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;liyao-spring-boot3-starter-auth&lt;/code&gt; 是一个基于 Spring Boot 3 的认证组件，提供了用户认证、权限校验等功能，可以快速集成到 Spring Boot 3 项目中，简化认证和授权的开发工作。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;功能特性 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;用户登录认证&lt;/li&gt;
&lt;li&gt;基于注解的权限校验&lt;/li&gt;
&lt;li&gt;可配置的路径过滤&lt;/li&gt;
&lt;li&gt;支持用户角色管理&lt;/li&gt;
&lt;li&gt;与 Spring Boot 3 无缝集成&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;安装方法 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;依赖可能非最新版本，请前往&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/liyao-spring-boot3-starter-auth" rel="external" target="_blank"&gt;maven&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;获取最新版本&lt;/div&gt;
 

&lt;/div&gt;

&lt;p&gt;1、在项目的 &lt;code&gt;pom.xml&lt;/code&gt; 文件中添加以下依赖&lt;/p&gt;</description></item><item><title>pagination</title><link>https://xiaoying.org.cn/pages/3dccbb/</link><pubDate>Thu, 27 Mar 2025 08:31:18 +0000</pubDate><guid>https://xiaoying.org.cn/pages/3dccbb/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;分页组件&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d8c95f2" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 ...
 &amp;lt;Pagination
 v-model:limit=&amp;#34;page.pageSize&amp;#34;
 v-model:page=&amp;#34;page.current&amp;#34;
 :total=&amp;#34;total&amp;#34;
 @pagination=&amp;#34;getUser&amp;#34;
 &amp;gt;
 &amp;lt;/Pagination&amp;gt;
 ...
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script lang=&amp;#34;ts&amp;#34; setup&amp;gt;
import { Pagination } from &amp;#34;liyao-vue-common&amp;#34;

const page: Record&amp;lt;string, any&amp;gt; = ref&amp;lt;UserQueryRequest&amp;gt;({
 current: 1,
 pageSize: 10
});

let total: number;

onMounted(() =&amp;gt; {
 getUser();
});

 
function getUser() {
 return new Promise((resolve) =&amp;gt; {
 // 后端获取数据接口...
 UserControllerService.listPageVo(page.value).then((res) =&amp;gt; {
 ...
 total = parseInt(res.data?.total);
 ...
 });
 });
}

&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>Chrome开启GeminiAI</title><link>https://xiaoying.org.cn/pages/bc4453/</link><pubDate>Wed, 04 Feb 2026 18:29:56 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bc4453/</guid><description>&lt;h1 id="-gemini-ai--auto-browse-"&gt;谷歌重大更新：国内手动开启 Gemini AI 侧边栏与 Auto Browse 自动浏览全攻略 &lt;a href="#-gemini-ai--auto-browse-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="-"&gt;🛠️ 功能亮点 &lt;a href="#-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Google Chrome 集成 Gemini 3 模型后，已从单一工具转变为智能助手：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Gemini 侧边栏 (Side Panel)：&lt;/strong&gt; 无需切换标签页即可总结内容、对比评论或同步日历。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto Browse (自动浏览)：&lt;/strong&gt; 具备代理能力 (Agentic Action)，可代劳预订、填表、收集文件或智能购物。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nano Banana：&lt;/strong&gt; 支持通过提示词直接在线修改网页图像。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;个人智能化：&lt;/strong&gt; 具备长期记忆，根据历史对话提供个性化建议。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="-local-state-"&gt;第一步：修改 Local State 配置文件 &lt;a href="#-local-state-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;注意：操作前请彻底关闭 Chrome 浏览器并备份该文件。&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id="heading"&gt;文件路径 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Windows:&lt;/strong&gt; &lt;code&gt;%LOCALAPPDATA%\Google\Chrome\User Data\Local State&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;macOS:&lt;/strong&gt; &lt;code&gt;~/Library/Application Support/Google/Chrome/Local State&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Linux:&lt;/strong&gt; &lt;code&gt;~/.config/google-chrome/Local State&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="heading-1"&gt;编辑内容 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;使用文本编辑器（如记事本、VS Code）打开 &lt;code&gt;Local State&lt;/code&gt; 文件，搜索并修改以下三项：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;variations_permanent_consistency_country&lt;/code&gt;: 将值由 &lt;code&gt;[&amp;quot;版本号&amp;quot;,&amp;quot;cn&amp;quot;]&lt;/code&gt; 改为 &lt;code&gt;[&amp;quot;版本号&amp;quot;,&amp;quot;us&amp;quot;]&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;variations_country&lt;/code&gt;: 将值由 &lt;code&gt;&amp;quot;cn&amp;quot;&lt;/code&gt; 改为 &lt;code&gt;&amp;quot;us&amp;quot;&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_glic_eligible&lt;/code&gt;: 将值由 &lt;code&gt;false&lt;/code&gt; 改为 &lt;code&gt;true&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="-chrome-flags-"&gt;第二步：配置 Chrome Flags 标志位 &lt;a href="#-chrome-flags-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;在 Chrome 地址栏输入：&lt;code&gt;chrome://flags&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;搜索以下项并将其状态从 &lt;code&gt;Default&lt;/code&gt; 修改为 &lt;strong&gt;&lt;code&gt;Enabled&lt;/code&gt;&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;#glic&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#glic-side-panel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="heading-2"&gt;第三步：语言与环境设置 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;修改首选语言：&lt;/strong&gt; * 进入 Chrome 设置 -&amp;gt; &lt;strong&gt;语言 (Languages)&lt;/strong&gt;。
&lt;ul&gt;
&lt;li&gt;添加 &lt;strong&gt;English&lt;/strong&gt;，点击右侧三个点，选择“置顶”并设置为浏览器显示语言。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;注：若不使用英文界面，可能仅能使用“帮我写 (Help me write)”功能，无法开启完整智能体。&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网络环境：&lt;/strong&gt; 必须确保处于&lt;strong&gt;美国节点&lt;/strong&gt;网络环境下运行。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重启浏览器：&lt;/strong&gt; 重启并登录 Chrome 后，右上角会出现 &lt;strong&gt;Gemini 图标&lt;/strong&gt;，点击即可开启侧边栏。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="--1"&gt;💡 自动化进阶工具 &lt;a href="#--1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;打开powershell执行以下命令即可&lt;/p&gt;</description></item><item><title>login</title><link>https://xiaoying.org.cn/login/</link><pubDate>Thu, 02 Oct 2025 15:22:25 +0000</pubDate><guid>https://xiaoying.org.cn/login/</guid><description/></item><item><title>about</title><link>https://xiaoying.org.cn/about/</link><pubDate>Tue, 16 Sep 2025 00:00:00 +0000</pubDate><guid>https://xiaoying.org.cn/about/</guid><description/></item><item><title>归档</title><link>https://xiaoying.org.cn/archives/</link><pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate><guid>https://xiaoying.org.cn/archives/</guid><description/></item><item><title>pandas 基础操作</title><link>https://xiaoying.org.cn/pages/5cde20/</link><pubDate>Thu, 24 Jul 2025 14:39:10 +0000</pubDate><guid>https://xiaoying.org.cn/pages/5cde20/</guid><description>&lt;p&gt;热门数据分析项目推荐&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;pandas-dev/pandas ⭐ 43.8k
GitHub地址: &lt;a href="https://github.com/pandas-dev/pandas" rel="external" target="_blank"&gt;https://github.com/pandas-dev/pandas&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简介: Python数据分析的核心库，提供数据结构和数据分析工具
适合: 必学基础库，所有数据分析项目的基础&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;ydataai/ydata-profiling ⭐ 12.4k
GitHub地址: &lt;a href="https://github.com/ydataai/ydata-profiling" rel="external" target="_blank"&gt;https://github.com/ydataai/ydata-profiling&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简介: 一行代码生成数据质量报告和探索性数据分析
适合: 初学者快速了解数据集特征&lt;/p&gt;</description></item><item><title>模板转换器</title><link>https://xiaoying.org.cn/pages/da4bbe/</link><pubDate>Tue, 15 Apr 2025 18:39:21 +0000</pubDate><guid>https://xiaoying.org.cn/pages/da4bbe/</guid><description>&lt;h1 id="spring-boot--velocity"&gt;Spring Boot Velocity转换器 &lt;a href="#spring-boot--velocity" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这是一个用于将Java、Vue、TS和XML文件转换为Velocity模板。这个starter可以帮助开发者快速实现代码生成功能，特别适用于需要从实体类生成VO类、表单类等场景。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;特性 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;支持多种文件类型转换：Java、Vue、TS、XML&lt;/li&gt;
&lt;li&gt;自动检测文件类型并应用相应的转换规则&lt;/li&gt;
&lt;li&gt;支持实体类与VO类的转换&lt;/li&gt;
&lt;li&gt;支持包名、模块名的自定义替换&lt;/li&gt;
&lt;li&gt;支持批量处理（ZIP文件）&lt;/li&gt;
&lt;li&gt;自动变量替换和模板生成&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;安装 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;&lt;p&gt;依赖可能非最新版本，请前往maven获取最新版本&lt;/p&gt;
&lt;p&gt;&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/velocityConverter-spring-boot-starter" rel="external" target="_blank"&gt;Spring Boot 2&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;地址&lt;/p&gt;</description></item><item><title>table</title><link>https://xiaoying.org.cn/pages/5d6721/</link><pubDate>Fri, 04 Apr 2025 06:01:30 +0000</pubDate><guid>https://xiaoying.org.cn/pages/5d6721/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;基于&lt;code&gt;el-table&lt;/code&gt;封装的表单&lt;/p&gt;
&lt;h2 id="heading-1"&gt;可选参数 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;isPopover&lt;/code&gt;为false为表单，为true则为Select选择器，选择的内容为表单内容&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ba13181" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 定义接收的属性
export interface ISelectConfig&amp;lt;T = any&amp;gt; {
 // 宽度
 width?: string;
 // 占位符
 placeholder?: string;
 // popover组件属性
 popover?: Partial&amp;lt;Omit&amp;lt;PopoverProps, &amp;#34;visible&amp;#34; | &amp;#34;v-model:visible&amp;#34;&amp;gt;&amp;gt;;
 // 列表的网络请求函数(需返回promise)
 indexAction: (_queryParams: T) =&amp;gt; Promise&amp;lt;any&amp;gt;;
 // 主键名(跨页选择必填,默认为id)
 pk?: string;
 // 多选
 multiple?: boolean;
 // 表单项
 formItems: Array&amp;lt;{
 // 组件类型(如input,select等)
 type?: &amp;#34;input&amp;#34; | &amp;#34;select&amp;#34; | &amp;#34;tree-select&amp;#34; | &amp;#34;date-picker&amp;#34;;
 // 标签文本
 label: string;
 // 键名
 prop: string;
 // 组件属性
 attrs?: IObject;
 // 初始值
 initialValue?: any;
 // 可选项(适用于select组件)
 options?: { label: string; value: any }[];
 }&amp;gt;;
 // 列选项
 tableColumns: Array&amp;lt;{
 type?: &amp;#34;default&amp;#34; | &amp;#34;selection&amp;#34; | &amp;#34;index&amp;#34; | &amp;#34;expand&amp;#34;;
 label?: string;
 prop?: string;
 width?: string | number;
 [key: string]: any;
 }&amp;gt;;
}

const props = withDefaults(
 defineProps&amp;lt;{
 selectConfig: ISelectConfig;
 isPopover?: boolean; // 属性控制弹出框行为
 }&amp;gt;(),
 {
 isPopover: false //为false为表单，为true则为Select选择器
 }
);

// 自定义事件
const emit = defineEmits&amp;lt;{
 confirmClick: [selection: any[]];
}&amp;gt;();&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;使用示例 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;select.ts&lt;/p&gt;</description></item><item><title>GPIO概述与配置</title><link>https://xiaoying.org.cn/pages/f42760/</link><pubDate>Mon, 20 Jan 2025 16:56:44 +0000</pubDate><guid>https://xiaoying.org.cn/pages/f42760/</guid><description>&lt;p&gt;基于STM32F429II的GPIO配置与使用的代码示例，包括输入模式、输出模式和外部中断模式的实现。代码基于HAL库开发。&lt;/p&gt;
&lt;h2 id="gpio"&gt;GPIO输出模式 &lt;a href="#gpio" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以下代码将GPIOA的第0引脚配置为推挽输出模式，并控制其输出高电平和低电平。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cd3cd8a" class="language-c wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;#include &amp;#34;stm32f4xx_hal.h&amp;#34;

void SystemClock_Config(void);
void GPIO_Init(void);

int main(void)
{
 HAL_Init(); // 初始化HAL库
 SystemClock_Config(); // 配置系统时钟
 GPIO_Init(); // 初始化GPIO

 while (1)
 {
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); // 设置GPIOA的第0引脚为高电平
 HAL_Delay(1000); // 延时1秒

 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); // 设置GPIOA的第0引脚为低电平
 HAL_Delay(1000); // 延时1秒
 }
}

void GPIO_Init(void)
{
 GPIO_InitTypeDef GPIO_InitStruct = {0};

 // 使能GPIOA时钟
 __HAL_RCC_GPIOA_CLK_ENABLE();

 // 配置GPIOA的第0引脚为推挽输出模式，无上拉下拉，速度为高速
 GPIO_InitStruct.Pin = GPIO_PIN_0;
 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
 GPIO_InitStruct.Pull = GPIO_NOPULL;
 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
 HAL_GPIO_Init(GPIOA, &amp;amp;GPIO_InitStruct);
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="gpio-1"&gt;GPIO输入模式 &lt;a href="#gpio-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以下代码将GPIOB的第0引脚配置为输入模式，并读取其电平状态。&lt;/p&gt;</description></item><item><title>常用网址</title><link>https://xiaoying.org.cn/pages/e22e65/</link><pubDate>Fri, 25 Aug 2023 11:43:46 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e22e65/</guid><description>&lt;h2 id="vuepress-plugin"&gt;vuepress-plugin &lt;a href="#vuepress-plugin" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/vuepress/awesome-vuepress" rel="external" target="_blank"&gt;awesome-vuepress&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://vuepress-community.netlify.app/zh/" rel="external" target="_blank"&gt;VuePress 社区&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>MyBatis Plus使用</title><link>https://xiaoying.org.cn/pages/c3fa0c/</link><pubDate>Thu, 24 Aug 2023 10:48:10 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c3fa0c/</guid><description>&lt;p&gt;::: info 提示&lt;/p&gt;
&lt;p&gt;maven依赖&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="71c6196" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;com.baomidou&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;mybatis-plus-boot-starter&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.5.3.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;yml配置&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8de8e0a" class="language-yaml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;mybatis-plus:
 configuration:
 map-underscore-to-camel-case: false
 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 global-config:
 db-config:
 logic-delete-field: isDelete # 全局逻辑删除的实体字段名
 logic-delete-value: 1 # 逻辑已删除值（默认为 1）
 logic-not-delete-value: 0 # 逻辑未删除值（默认为 0）&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2 id="crud"&gt;常用CRUD及基本流程 &lt;a href="#crud" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="fe267d2" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;基本流程 mapper.xml =&amp;gt; mapper =&amp;gt; serviceImpl =&amp;gt; service =&amp;gt; controller =&amp;gt; 前端&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="crud-1"&gt;CRUD使用 &lt;a href="#crud-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;mapper，mapper.xml及基本的service层由MybatisX生成，基本使用直接在controller层调用即可，如下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7fa7d67" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; @GetMapping(&amp;#34;/&amp;#34;)
 public Website listConfig() {
 QueryWrapper&amp;lt;Website&amp;gt; queryWrapper = new QueryWrapper&amp;lt;&amp;gt;();
 queryWrapper.select(&amp;#34;config&amp;#34;);
 return websiteService.getOne(queryWrapper);
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;也可在service层自定义接口，serviceImpl层写具体逻辑，controller层调用&lt;/p&gt;</description></item><item><title>npm 和 yarn</title><link>https://xiaoying.org.cn/pages/6676cf/</link><pubDate>Mon, 21 Aug 2023 09:11:30 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6676cf/</guid><description>&lt;p&gt;::: info 提示&lt;/p&gt;
&lt;p&gt;作为前端开发者我们经常会使用npm或yarn，我们都知道npm和yarn默认镜像在国外，国内访问这些镜像速度会比较慢，下面介绍修改npm和yarn源的方法&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="heading"&gt;清除缓存 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="npm"&gt;npm &lt;a href="#npm" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d42b05e" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm cache clean --force&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="yarn"&gt;yarn &lt;a href="#yarn" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e4256c0" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn cache clean&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="pnpm"&gt;pnpm &lt;a href="#pnpm" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="590c22e" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;pnpm store prune&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="npmyarn"&gt;npm和yarn源的简单修改（以淘宝镜像为例） &lt;a href="#npmyarn" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="npm-1"&gt;npm &lt;a href="#npm-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h6 id="heading-1"&gt;临时修改（只生效一次） &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h6&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2d7a126" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install 包的名字 --registry https://registry.npmmirror.com&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h6 id="npm-2"&gt;设置npm的配置项（全局配置） &lt;a href="#npm-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h6&gt;
&lt;p&gt;查看npm源的当前地址&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e7c51cd" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm config get registry&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;设置淘宝镜像&lt;/p&gt;</description></item><item><title>numpy</title><link>https://xiaoying.org.cn/pages/7461eb/</link><pubDate>Thu, 24 Jul 2025 14:44:53 +0000</pubDate><guid>https://xiaoying.org.cn/pages/7461eb/</guid><description>&lt;p&gt;1111111111111111&lt;/p&gt;</description></item><item><title>keil调试</title><link>https://xiaoying.org.cn/pages/0c6c87/</link><pubDate>Tue, 21 Jan 2025 10:53:44 +0000</pubDate><guid>https://xiaoying.org.cn/pages/0c6c87/</guid><description>&lt;p&gt;在工程配置菜单中，User选项卡，编译后执行的命令，设置为&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b7b3c06" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;fromelf --bin -o &amp;#34;$L@L.bin&amp;#34; &amp;#34;#L&amp;#34;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;当然也可以使用绝对路径的方式，需要指定fromelf文件的路径，输出BIN文件的路径和生成的AXF文件的路径。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=480 480w,
 https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=768 768w,
 https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202501211054465.jpeg?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>springboot2引入swagger3</title><link>https://xiaoying.org.cn/pages/438816/</link><pubDate>Thu, 24 Aug 2023 10:48:32 +0000</pubDate><guid>https://xiaoying.org.cn/pages/438816/</guid><description>&lt;h2 id="heading"&gt;引入依赖 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://doc.xiaominfo.com/docs/quick-start#openapi3" rel="external" target="_blank"&gt;最新版本&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="54d77d2" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;com.github.xiaoymin&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;knife4j-openapi3-spring-boot-starter&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;最新版本&amp;lt;/version&amp;gt; 
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="yml"&gt;填写yml配置文件 &lt;a href="#yml" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;dev环境&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="89e9530" class="language-yaml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;springdoc:
 swagger-ui:
 path: /swagger-ui.html
 tags-sorter: alpha
 operations-sorter: method
 api-docs:
 path: /v3/api-docs
 group-configs:
 - group: &amp;#39;default&amp;#39;
 paths-to-match: &amp;#39;/**&amp;#39;
 packages-to-scan: com.yupi.springbootinit.controller
# knife4j的增强配置，不需要增强可以不配
knife4j:
 enable: true
 setting:
 language: zh_cn&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;prod环境&lt;/p&gt;</description></item><item><title>RTC实时时钟</title><link>https://xiaoying.org.cn/pages/b35fb7/</link><pubDate>Wed, 12 Feb 2025 17:46:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/b35fb7/</guid><description>&lt;h2 id="rtc-"&gt;RTC 简介 &lt;a href="#rtc-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RTC（Real Time Clock），即实时时钟，类似于钟表一般，能够持续记录时间，为程序提供精确的日期和时间信息，即使在断电期间也能确保准确运行。&lt;/p&gt;
&lt;h3 id="heading"&gt;原理和特点 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在STM32中，存在两个时钟源：高速时钟（8 MHz）和低速时钟（32.768 kHz）。高速时钟用于驱动CPU、外设和定时器等核心组件，而低速时钟则负责管理看门狗和RTC等功能。&lt;/li&gt;
&lt;li&gt;RTC依赖低速时钟运行。&lt;/li&gt;
&lt;li&gt;RTC模块内部包含了一个独立的32位寄存器来保存当前的时间戳信息。&lt;/li&gt;
&lt;li&gt;低速时钟以极低的功耗运行，即使在断电情况下，通过备用电源（如纽扣电池），RTC也能持续运行以确保时间准确性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="rtc"&gt;RTC的一般使用方法 &lt;a href="#rtc" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;在CubeMX中找到Timers -&amp;gt; RTC，勾选Activate Clock Source，即可激活RTC时钟功能。&lt;/li&gt;
&lt;li&gt;即使学习板断电，RTC依然能够持续记录时间。&lt;/li&gt;
&lt;li&gt;HAL库的RTC驱动未实现日期的断电走时功能，即断电后时间可以继续走时，但日期会重置。&lt;/li&gt;
&lt;li&gt;keysking提供了RTC库，可以实现断电走时功能，具体代码见下文。&lt;/li&gt;
&lt;li&gt;需要获取当前日期和时间时，只需调用相应函数即可实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="rtc-1"&gt;RTC实时时钟实现 &lt;a href="#rtc-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;工程配置 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;**开启外部晶振：**在Pinout&amp;amp;Configuration -&amp;gt; System Core -&amp;gt; RCC 页面，将 High Speed Clock (HSE) 以及 Low Speed Clock (LSE) 都配置为 Crystal/Ceramic Resonator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202502121751741.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202502121751741.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202502121751741.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202502121751741.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202502121751741.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202502121751741.png?w=2400 2400w
 " sizes="100vw" alt="配置时钟源" loading="lazy"&gt;


&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**配置主时钟频率：**在Clock Configuration 页面，将PLL Source 选择为 HSE，将System Clock Mux 选择为 PLLCLK，然后在HCLK (MHz) 输入72并回车，将HCLK频率配置为 72 MHz&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202502121751901.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202502121751901.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202502121751901.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202502121751901.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202502121751901.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202502121751901.png?w=2400 2400w
 " sizes="100vw" alt="时钟配置" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>EasyCaptcha验证码存入redis的使用</title><link>https://xiaoying.org.cn/pages/0b3b5e/</link><pubDate>Thu, 24 Aug 2023 10:40:12 +0000</pubDate><guid>https://xiaoying.org.cn/pages/0b3b5e/</guid><description>&lt;h2 id="maven"&gt;引入Maven依赖 &lt;a href="#maven" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="82fa722" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- EasyCaptcha --&amp;gt;
&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;com.github.whvcse&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;easy-captcha&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;1.6.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;

 &amp;lt;!-- redis --&amp;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-data-redis&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;org.springframework.session&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;spring-session-data-redis&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="yml"&gt;yml配置 &lt;a href="#yml" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="581e459" class="language-yaml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 验证码配置
easy-captcha:
 # 验证码类型: arithmetic-算术
 type: arithmetic
 # 验证码有效时间(单位：秒)
 ttl: 300
 
# Redis 配置
spring
 redis:
 database: 1
 host: localhost
 port: 6379
 timeout: 5000
 password: 123456
 lettuce:
 pool:
 # 连接池最大连接数 默认8 ，负数表示没有限制
 max-active: 8
 # 连接池最大阻塞等待时间（使用负值表示没有限制） 默认-1
 max-wait: -1
 # 连接池中的最大空闲连接 默认8
 max-idle: 8
 # 连接池中的最小空闲连接 默认0
 min-idle: 0&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;验证码类型枚举 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="604092e" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;public enum CaptchaTypeEnum {

 /**
 * 算数
 */
 ARITHMETIC,
 /**
 * 中文
 */
 CHINESE,
 /**
 * 中文闪图
 */
 CHINESE_GIF,
 /**
 * 闪图
 */
 GIF,
 SPEC
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;配置类 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="captcha"&gt;Captcha配置类 &lt;a href="#captcha" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b8df894" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@ConfigurationProperties(prefix = &amp;#34;easy-captcha&amp;#34;)
@Configuration
@Data
public class CaptchaConfig {

 /**
 * 验证码类型
 */
 private CaptchaTypeEnum type = CaptchaTypeEnum.ARITHMETIC;


 /**
 * 验证码缓存过期时间(单位:秒)
 */
 private long ttl = 300L;

 /**
 * 验证码内容长度
 */
 private int length = 4;
 /**
 * 验证码宽度
 */
 private int width = 120;
 /**
 * 验证码高度
 */
 private int height = 36;


 /**
 * 验证码字体
 */
 private String fontName = &amp;#34;Verdana&amp;#34;;

 /**
 * 字体风格
 */
 private Integer fontStyle = Font.PLAIN;

 /**
 * 字体大小
 */
 private int fontSize = 20;


}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="redis"&gt;redis配置类 &lt;a href="#redis" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3dd0c2e" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Configuration
@EnableCaching //开启注解
public class RedisConfig extends CachingConfigurerSupport {
 /**
 * retemplate相关配置
 * 序列化配置，如果没有配置序列化的话可能会出现往redis存了值，但是获取不到
 */
 @Bean
 public RedisTemplate&amp;lt;String, Object&amp;gt; redisTemplate(RedisConnectionFactory factory) {
 RedisTemplate&amp;lt;String, Object&amp;gt; template = new RedisTemplate&amp;lt;&amp;gt;();
 template.setConnectionFactory(factory);
 Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);
 ObjectMapper om = new ObjectMapper();
 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
 jacksonSeial.setObjectMapper(om);
 template.setValueSerializer(jacksonSeial);
 template.setKeySerializer(new StringRedisSerializer());
 template.setHashKeySerializer(new StringRedisSerializer());
 template.setHashValueSerializer(jacksonSeial);
 template.afterPropertiesSet();
 return template;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="dto"&gt;添加dto类 &lt;a href="#dto" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c6e6ac1" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Schema(description =&amp;#34;验证码校验对象&amp;#34;)
@Builder
@Data
public class CaptchaCheck {

 @Schema(description = &amp;#34;验证码缓存key&amp;#34;)
 private String verifyCodeKey;

 @Schema(description = &amp;#34;用户输入验证码&amp;#34;)
 private String verifyCode;
}

@Schema(description =&amp;#34;验证码响应对象&amp;#34;)
@Builder
@Data
public class CaptchaResult {

 @Schema(description = &amp;#34;验证码缓存key&amp;#34;)
 private String verifyCodeKey;

 @Schema(description = &amp;#34;验证码图片Base64字符串&amp;#34;)
 private String verifyCodeBase64;

}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;验证码生成 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b667569" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Component
@RequiredArgsConstructor
public class EasyCaptchaProducer {

 private final CaptchaConfig captchaConfig;

 public Captcha getCaptcha() {
 Captcha captcha;
 int width = captchaConfig.getWidth();
 int height = captchaConfig.getHeight();
 int length = captchaConfig.getLength();
 String fontName = captchaConfig.getFontName();

 switch (captchaConfig.getType()) {
 case ARITHMETIC:
 captcha = new ArithmeticCaptcha(width, height);
 //固定设置为两位，图片为算数运算表达式
 captcha.setLen(2);
 break;
 case CHINESE:
 captcha = new ChineseCaptcha(width, height);
 captcha.setLen(length);
 break;
 case CHINESE_GIF:
 captcha = new ChineseGifCaptcha(width, height);
 captcha.setLen(length);
 break;
 case GIF:
 captcha = new GifCaptcha(width, height);//最后一位是位数
 captcha.setLen(length);
 break;
 case SPEC:
 captcha = new SpecCaptcha(width, height);
 captcha.setLen(length);
 break;
 default:
 throw new RuntimeException(&amp;#34;验证码配置信息错误！正确配置查看 CaptchaTypeEnum &amp;#34;);
 }
 captcha.setFont(new Font(fontName, captchaConfig.getFontStyle(), captchaConfig.getFontSize()));
 return captcha;

 }


}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="redis-1"&gt;获取验证码并将验证码文本缓存至Redis，用于登录校验 &lt;a href="#redis-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c88e0b4" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Component
@RequiredArgsConstructor
public class EasyCaptchaService {

 private final EasyCaptchaProducer easyCaptchaProducer;

 private final RedisTemplate&amp;lt;String, String&amp;gt; redisTemplate;

 private final CaptchaConfig captchaConfig;

 /**
 * 获取验证码
 *
 * @return
 */
 public CaptchaResult getCaptcha() {
 // 获取验证码
 Captcha captcha = easyCaptchaProducer.getCaptcha();
 String captchaText = captcha.text(); // 验证码文本
 String captchaBase64 = captcha.toBase64(); // 验证码图片Base64字符串

 // 验证码文本缓存至Redis，用于登录校验
 String verifyCodeKey = IdUtil.fastSimpleUUID();
 redisTemplate.opsForValue().set(SecurityConstants.VERIFY_CODE_CACHE_PREFIX &amp;#43; verifyCodeKey, captchaText,
 captchaConfig.getTtl(), TimeUnit.SECONDS);

 return CaptchaResult.builder()
 .verifyCodeKey(verifyCodeKey)
 .verifyCodeBase64(captchaBase64)
 .build();
 }

}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;校验验证码 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e4d08a5" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Component
public class VerifyCodeFilter {

 public boolean doFilterInternal(String verifyCode, String verifyCodeKey, HttpServletRequest request) {

 // 缓存中的验证码
 RedisTemplate redisTemplate = SpringUtil.getBean(&amp;#34;redisTemplate&amp;#34;, RedisTemplate.class);
 Object cacheVerifyCode = redisTemplate.opsForValue().get(SecurityConstants.VERIFY_CODE_CACHE_PREFIX &amp;#43; verifyCodeKey);
 if (cacheVerifyCode == null) {
 throw new BusinessException(ErrorCode.VERIFY_CODE_TIMEOUT);
 }
 // 验证码比对
 if (!StrUtil.equals(verifyCode, Convert.toStr(cacheVerifyCode))) {
 throw new BusinessException(ErrorCode.VERIFY_CODE_ERROR);
 }
 return true;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;验证码接口 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5e11d35" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Tag(name = &amp;#34;CaptchaController&amp;#34;)
@RequestMapping(&amp;#34;/captcha&amp;#34;)
@RestController
@Slf4j
public class CaptchaController {

 private final EasyCaptchaService easyCaptchaService;
 private final VerifyCodeFilter verifyCodeFilter;


 public CaptchaController(EasyCaptchaService easyCaptchaService, VerifyCodeFilter verifyCodeFilter) {
 this.easyCaptchaService = easyCaptchaService;
 this.verifyCodeFilter = verifyCodeFilter;
 }

 @Operation(summary = &amp;#34;获取验证码&amp;#34;)
 @PostMapping(&amp;#34;/get&amp;#34;)
 public BaseResponse&amp;lt;CaptchaResult&amp;gt; getCaptcha() {
 CaptchaResult captcha = easyCaptchaService.getCaptcha();
 return ResultUtils.success(captcha);
 }

 @Operation(summary = &amp;#34;校验验证码&amp;#34;)
 @PostMapping(&amp;#34;/check&amp;#34;)
 public BaseResponse&amp;lt;Boolean&amp;gt; checkCaptcha(@RequestBody CaptchaCheck CaptchaCheck, HttpServletRequest request) {
 String verifyCode = CaptchaCheck.getVerifyCode();
 String verifyCodeKey = CaptchaCheck.getVerifyCodeKey();
 boolean result = verifyCodeFilter.doFilterInternal(verifyCode, verifyCodeKey, request);
 return ResultUtils.success(result);
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>常用方法</title><link>https://xiaoying.org.cn/pages/c92585/</link><pubDate>Thu, 24 Aug 2023 10:48:23 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c92585/</guid><description>&lt;h2 id="heading"&gt;查询数据是否存在 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="db0aeca" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;//导入依赖
&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;org.springframework.data&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;spring-data-jpa&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.0.5&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;

 // 创建类
@Repository
public interface UserRepository extends CrudRepository&amp;lt;User, Long&amp;gt; {
 // CrudRepository内置boolean existsById(ID id)，这个方法将会返回一个布尔值，表示该ID是否存在。
}

//调用
 @GetMapping(&amp;#34;/delete&amp;#34;)
 public Result&amp;lt;String&amp;gt; deleteById(String id){
 boolean existsById = postEsDao.existsById(id);
 if (!existsById) {
 return Result.failure(ErrorCode.NOT_FOUND_ERROR);
 }
 postEsDao.deleteById(id);
 return Result.success(&amp;#34;删除成功&amp;#34;);
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="yml"&gt;yml文件常用配置 &lt;a href="#yml" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5e60c02" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 url: jdbc:mysql://localhost:3306/mybatisdemo
 username: root
 password: Hik@1234
 mvc:
 pathmatch:
 matching-strategy: ant_path_matcher // 使用ant_path_matcher策略来匹配请求的URL路径
 validation:
 enabled: true
 application:
 name: spring-boot
 profiles:
 active: dev
 jackson:
 default-property-inclusion: non_null //返回消息为null则不显示
 date-format: yyyy-MM-dd HH:mm:ss // 全局格式化时间
 elasticsearch:
 uris: http://localhost:9200
 username: root
 password: 123456

mybatis-plus:
 configuration:
 call-setters-on-nulls: true // 如果数据库字段的值为NULL,将NULL作为参数传递给setter方法,避免了空指针异常。
 map-underscore-to-camel-case: false
 log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 sql-parser-cache: true
 global-config:
 db-config:
 logic-delete-field: isDelete
 logic-delete-value: 1
 logic-not-delete-value: 0
 column-format: &amp;#39;&amp;#39;
 
knife4j:
 enable: true
 setting:
 language: zh_cn&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="mapstruct"&gt;MapStruct代码映射工具 &lt;a href="#mapstruct" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;它简化了Java Bean之间映射的过程。它在编译时生成映射代码，从而消除了开发人员手动编写重复且容易出错的映射代码的需要。&lt;/p&gt;</description></item><item><title>Elasticsearch全文搜索</title><link>https://xiaoying.org.cn/pages/7498d0/</link><pubDate>Thu, 24 Aug 2023 10:48:13 +0000</pubDate><guid>https://xiaoying.org.cn/pages/7498d0/</guid><description>&lt;h2 id="-windows--elasticsearch-"&gt;在 Windows 上安装 Elasticsearch 作为服务 &lt;a href="#-windows--elasticsearch-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Elasticsearch 可以作为服务安装在后台运行，或者在启动时自动启动，无需任何用户交互。&lt;code&gt;elasticsearch-service.bat&lt;/code&gt;这可以通过文件夹中的脚本实现，&lt;code&gt;bin\&lt;/code&gt;该脚本允许从命令行安装、删除、管理或配置服务并可能启动和停止服务。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d18be31" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;D:\elasticsearch-7.17.9\bin&amp;gt;elasticsearch-service.bat

Usage: elasticsearch-service.bat install|remove|start|stop|manager [SERVICE_ID]&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;该脚本需要一个参数（要执行的命令），后跟一个指示服务 ID 的可选参数（在安装多个 Elasticsearch 服务时很有用）。&lt;/p&gt;
&lt;p&gt;可用的命令是：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;&lt;code&gt;install&lt;/code&gt;&lt;/th&gt;
 &lt;th&gt;将 Elasticsearch 安装为服务&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;remove&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;删除已安装的 Elasticsearch 服务（如果启动则停止该服务）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;start&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;启动 Elasticsearch 服务（如果已安装）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;stop&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;停止 Elasticsearch 服务（如果已启动）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;manager&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;启动用于管理已安装服务的 GUI&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading"&gt;添加依赖 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;要使用 Elasticsearch，需要添加 Elasticsearch 的 Java 客户端依赖。可以在项目的 &lt;code&gt;pom.xml&lt;/code&gt; 文件中添加以下依赖&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8fa6961" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&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-data-elasticsearch&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;配置连接信息 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4c3afa0" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;spring:
 elasticsearch:
 uris: http://localhost:9200
 socket-timeout: &amp;#34;10s&amp;#34;
 username: &amp;#34;user&amp;#34;
 password: &amp;#34;secret&amp;#34;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;创建实体类 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建一个Java类来表示您要存储在Elasticsearch中的数据。此类应该使用&lt;code&gt;@Document&lt;/code&gt;注解进行注释，并且每个字段都应该使用相应的注解进行注释，以指定字段名称、数据类型和Elasticsearch中的数据类型。&lt;/p&gt;</description></item><item><title>canal同步mysql数据到es中</title><link>https://xiaoying.org.cn/pages/e40320/</link><pubDate>Thu, 24 Aug 2023 10:48:15 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e40320/</guid><description>&lt;p&gt;::: info 提示&lt;/p&gt;
&lt;p&gt;maven依赖&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a1fac10" class="language-yaml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;com.alibaba.otter&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;canal.client&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;1.1.4&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;h2 id="mysqlbinlog"&gt;开启mysql的binlog &lt;a href="#mysqlbinlog" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用canal-server需要先准备mysql，对于自建 MySQL , 需要先开启 Binlog 写入功能，配置 binlog-format 为 ROW 模式&lt;/p&gt;
&lt;p&gt;vi /etc/my.cnf&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7e336f5" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;[mysqld]
log-bin=mysql-bin # 开启 binlog
binlog-format=ROW # 选择 ROW 模式
server_id=1 # 配置 MySQL replaction 需要定义，不要和 canal 的 slaveId 重复&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;配置完成后重启mysql，并查询是否配置生效：ON就是开启&lt;/p&gt;
&lt;p&gt;systemctl restart mysqld&lt;/p&gt;
&lt;p&gt;可以进入数据库再次查看下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5f5dbd3" class="language-sql wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;mysql&amp;gt; show variables like &amp;#39;log_bin&amp;#39;;
&amp;#43;---------------&amp;#43;-------&amp;#43;
| Variable_name | Value |
&amp;#43;---------------&amp;#43;-------&amp;#43;
| log_bin | ON |
&amp;#43;---------------&amp;#43;-------&amp;#43;
1 row in set (0.01 sec)
 
mysql&amp;gt; show variables like &amp;#39;binlog_format%&amp;#39;;
&amp;#43;---------------&amp;#43;-------&amp;#43;
| Variable_name | Value |
&amp;#43;---------------&amp;#43;-------&amp;#43;
| binlog_format | ROW |
&amp;#43;---------------&amp;#43;-------&amp;#43;
1 row in set (0.00 sec)&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="mysql"&gt;mysql用户数据准备 &lt;a href="#mysql" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建一个canal用户并对其进行授权&lt;/p&gt;</description></item><item><title>SpringSecurity使用</title><link>https://xiaoying.org.cn/pages/c47a32/</link><pubDate>Fri, 15 Sep 2023 09:24:20 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c47a32/</guid><description>&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Spring Security&lt;/strong&gt; 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架&lt;strong&gt;Shiro&lt;/strong&gt;，它提供了更丰富的功能，社区资源也比Shiro丰富。&lt;/p&gt;
&lt;p&gt;一般来说中大型的项目都是使用&lt;strong&gt;SpringSecurity&lt;/strong&gt; 来做安全框架。小项目有Shiro的比较多，因为相比与SpringSecurity，Shiro的上手更加的简单。&lt;/p&gt;
&lt;p&gt;一般Web应用的需要进行&lt;strong&gt;认证&lt;/strong&gt;和&lt;strong&gt;授权&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;​	&lt;strong&gt;认证：验证当前访问系统的是不是本系统的用户，并且要确认具体是哪个用户&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;​	&lt;strong&gt;授权：经过认证后判断当前用户是否有权限进行某个操作&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;而认证和授权也是SpringSecurity作为安全框架的核心功能。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;快速入门 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;准备工作 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;我们先要搭建一个简单的SpringBoot工程&lt;/p&gt;
&lt;p&gt;① 设置父工程 添加依赖&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3c431ad" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;parent&amp;gt;
 &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;spring-boot-starter-parent&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;2.5.0&amp;lt;/version&amp;gt;
 &amp;lt;/parent&amp;gt;
 &amp;lt;dependencies&amp;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;/dependency&amp;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;optional&amp;gt;true&amp;lt;/optional&amp;gt;
 &amp;lt;/dependency&amp;gt;
 &amp;lt;/dependencies&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;② 创建启动类&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="68fa043" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@SpringBootApplication
public class SecurityApplication {

 public static void main(String[] args) {
 SpringApplication.run(SecurityApplication.class,args);
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;③ 创建Controller&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="91c8e05" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

 @RequestMapping(&amp;#34;/hello&amp;#34;)
 public String hello(){
 return &amp;#34;hello&amp;#34;;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="springsecurity"&gt;引入SpringSecurity &lt;a href="#springsecurity" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在SpringBoot项目中使用SpringSecurity我们只需要引入依赖即可实现入门案例。&lt;/p&gt;</description></item><item><title>StringUtils 工具类使用</title><link>https://xiaoying.org.cn/pages/fb0a8c/</link><pubDate>Tue, 03 Oct 2023 22:38:19 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fb0a8c/</guid><description>&lt;h2 id="heading"&gt;概览 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;大部分方法都提供了很多重载方法，比如不区分大小写&lt;code&gt;xxIgnoreCase&lt;/code&gt;、匹配任何&lt;code&gt;xxAny&lt;/code&gt;、还有参数类型不同、参数个数不同的重载等，能适应绝大多数业务场景的需求。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202310032244257.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202310032244257.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202310032244257.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202310032244257.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202310032244257.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202310032244257.png?w=2400 2400w
 " sizes="100vw" alt="" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="heading-1"&gt;静态常量 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;StringUtils 提供了最常用的常量如下，使用定义的常量能让我们的代码更清晰。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202310032248030.jpg?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202310032248030.jpg?w=480 480w,
 https://img.xiaoying.org.cn/img/202310032248030.jpg?w=768 768w,
 https://img.xiaoying.org.cn/img/202310032248030.jpg?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202310032248030.jpg?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202310032248030.jpg?w=2400 2400w
 " sizes="100vw" alt="1532358237" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="heading-2"&gt;花式截取字符串 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ef11dba" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testSubstring() {
 // 最基本的截取
 System.out.println( StringUtils.substring(&amp;#34;abcde&amp;#34;, 1, 2) ); // b
 // 截取前半部分
 System.out.println( StringUtils.substringBefore(&amp;#34;role/site/admin-(1.site.1)&amp;#34;, &amp;#34;-(&amp;#34;) ); // role/site/admin
 // 截取后半部分
 System.out.println( StringUtils.substringAfter(&amp;#34;role/site/admin-(1.site.1)&amp;#34;, &amp;#34;-&amp;#34;) ); // (1.site.1)
 // 截取之间的
 System.out.println( StringUtils.substringBetween(&amp;#34;role/site/admin-(1.site.1)&amp;#34;, &amp;#34;(&amp;#34;, &amp;#34;)&amp;#34;) ); // 1.site.1
 // 截取左边的部分
 System.out.println( StringUtils.left(&amp;#34;aabbcc&amp;#34;, 4) ); // aabb
 // 截取右边的部分
 System.out.println( StringUtils.right(&amp;#34;aabbcc&amp;#34;, 4) ); // bbcc
 // 截取中间部分
 System.out.println( StringUtils.mid(&amp;#34;aabbcc&amp;#34;, 1, 2) ); // ab
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;各种判断空与非空 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c588551" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testIsEmpty() {
 // 判断是否为空 只有为 null 或 &amp;#34;&amp;#34; 的时候才会true
 System.out.println( StringUtils.isEmpty(&amp;#34; &amp;#34;) ); // false
 // 判断不为空
 System.out.println( StringUtils.isNotEmpty(&amp;#34; &amp;#34;) ); // true
 // 判断是否为空 null、&amp;#34;&amp;#34;、全空格 都为true
 System.out.println( StringUtils.isBlank(&amp;#34; &amp;#34;) ); // true
 // 判读不为空
 System.out.println( StringUtils.isNotBlank(&amp;#34; &amp;#34;) ); // false
 // 任何一个为空
 System.out.println( StringUtils.isAnyEmpty(&amp;#34;ab&amp;#34;, &amp;#34; &amp;#34;) ); // false
 // 任何一个为空
 System.out.println( StringUtils.isAnyBlank(&amp;#34;ab&amp;#34;, &amp;#34; &amp;#34;) ); // true
 // 没有为空的
 System.out.println( StringUtils.isNoneEmpty(&amp;#34;ab&amp;#34;, &amp;#34;&amp;#34;) ); // false
 // 所有的都为空
 System.out.println( StringUtils.isAllBlank(&amp;#34;ab&amp;#34;, &amp;#34; &amp;#34;) ); // false
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;判断是否相等 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ef40930" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testEqual() {
 // 判断是否相等 区分大小写
 System.out.println( StringUtils.equals(&amp;#34;ab&amp;#34;, &amp;#34;Ab&amp;#34;) ); // false
 // 判断是否相等 不区分大小写
 System.out.println( StringUtils.equalsIgnoreCase(&amp;#34;ab&amp;#34;, &amp;#34;Ab&amp;#34;) ); // true
 // 判断其中一个相等
 System.out.println( StringUtils.equalsAny(&amp;#34;ab&amp;#34;, &amp;#34;Ab&amp;#34;, &amp;#34;ab&amp;#34;, &amp;#34;abc&amp;#34;) ); // true
 // 判断其中一个相等
 System.out.println( StringUtils.equalsAnyIgnoreCase(&amp;#34;ab&amp;#34;, &amp;#34;Ab&amp;#34;, &amp;#34;abc&amp;#34;) ); // true
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-5"&gt;补齐 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="32e7e93" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testPad() {
 // 左边补齐
 System.out.println( StringUtils.leftPad(&amp;#34;abc&amp;#34;, 5, &amp;#34;x&amp;#34;) ); // xxabc
 // 右边补齐
 System.out.println( StringUtils.rightPad(&amp;#34;abc&amp;#34;, 5, &amp;#34;x&amp;#34;) ); // abcxx
 // 两边补齐
 System.out.println( StringUtils.center(&amp;#34;abc&amp;#34;, 5, &amp;#34;x&amp;#34;) ); // xabcx
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-6"&gt;缩短省略 &lt;a href="#heading-6" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="61d9c15" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testAbb() {
 // 共计10位数 超出省略 默认 ...
 System.out.println( StringUtils.abbreviate(&amp;#34;abcdefghijklmn&amp;#34;, 10) ); // abcdefg...
 // 指定省略符
 System.out.println( StringUtils.abbreviate(&amp;#34;abcdefghijklmn&amp;#34;, &amp;#34;***&amp;#34;, 10) ); // abcdefg***
 // 两边省略
 System.out.println( StringUtils.abbreviate(&amp;#34;abcdefghijklmn&amp;#34;, 5, 10) ); // ...fghi...
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-7"&gt;去掉控制字符和指定字符 &lt;a href="#heading-7" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2b918f9" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Test
public void testTrim() {
 // trim 主要用于去掉控制字符 ,即ASC码表小于等于32的字符，strip主要用于去掉指定字符，默认空格

 // 去掉两边空白
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.trim(&amp;#34; ab cd &amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [ab cd]
 // trim 去掉的是ASC码表小于等于32的字符(特殊字符)
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.trim(&amp;#34; \n ab cd &amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [ab cd]
 // trim 去掉的是ASC码表小于等于32的字符(特殊字符)
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.trim(&amp;#34; ab \n cd &amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [ab \n cd]
 // 如果为空则返回null
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.trimToNull(&amp;#34; &amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [null]
 // 如果为空返回空
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.trimToEmpty(null) &amp;#43; &amp;#34;]&amp;#34;); // []

 // strip 行为和trim基本一样，可以指定去掉的字符串
 char ch = 30;
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.strip(ch&amp;#43;&amp;#34; ab cd &amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [ab cd]
 // 去掉开头的字符，null默认为空格
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.stripStart(&amp;#34; ab cd &amp;#34;, null) &amp;#43; &amp;#34;]&amp;#34;); // [ab cd ]
 // 去掉开头的字符，null默认为空格
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.stripStart(&amp;#34;ab cd &amp;#34;, &amp;#34;a&amp;#34;) &amp;#43; &amp;#34;]&amp;#34;); // [b cd ]
 // 去掉末尾的空格
 System.out.println(&amp;#34;[&amp;#34; &amp;#43; StringUtils.stripEnd(&amp;#34; ab cd &amp;#34;, null) &amp;#43; &amp;#34;]&amp;#34;); // [ ab cd]&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>HTTP各种参数发送</title><link>https://xiaoying.org.cn/pages/bfdaa2/</link><pubDate>Thu, 05 Oct 2023 12:22:10 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bfdaa2/</guid><description>&lt;p&gt;利用Idea的HttpClient向SpringBoot发起各种请求参数。后端使用&lt;code&gt;@RequestParam&lt;/code&gt;，&lt;code&gt;@ModelAttribute&lt;/code&gt;，&lt;code&gt;@PathVariable&lt;/code&gt;，&lt;code&gt;@RequestBody&lt;/code&gt;，&lt;code&gt;@RequestPart&lt;/code&gt;去接收。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="spring-mvc--get-"&gt;spring mvc 中的参数接受之 GET 请求 &lt;a href="#spring-mvc--get-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Get 请求是没有 body 的，参数都是放在 url 上面。
根据在 url 参数格式不同，一共有下面这几种&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Path Variable&lt;/li&gt;
&lt;li&gt;Query&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="path-variable"&gt;path variable &lt;a href="#path-variable" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-pathvariable"&gt;使用 &lt;code&gt;@PathVariable&lt;/code&gt; &lt;a href="#-pathvariable" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b1255b9" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;GET http://localhost:7720/user/find/123/abc
 \ /
 这里的&amp;#34;123&amp;#34;和&amp;#34;abc&amp;#34;是参数&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;这种传参格式就如同名字一样&amp;quot;路径变量&amp;quot;，参数在路径上。&lt;/p&gt;
&lt;p&gt;针对这种传参方式后端可以这么接受。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c6d5974" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; // 在路径中用id占位，代表这个地方将会是参数
 @GetMapping(&amp;#34;find/{id}/{username}&amp;#34;)
 // 方法上面通过占位名称得到参数
 public R&amp;lt;Boolean&amp;gt; pathVariable(@PathVariable String id, @PathVariable String username) {
 log.info(id);
 log.info(username);
 return R.ok(true);
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="query-"&gt;query 传参 &lt;a href="#query-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-requestparam"&gt;使用 &lt;code&gt;@RequestParam&lt;/code&gt; &lt;a href="#-requestparam" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9669506" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;### GET http://localhost:7720/user/find?username=yupi&amp;amp;password=123456&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;在路径的最后用 &amp;ldquo;?&amp;rdquo; 隔开要传输的参数。 通过 &amp;ldquo;&amp;amp;&amp;rdquo; 分割多个 &lt;code&gt;key=value&lt;/code&gt;&lt;/p&gt;</description></item><item><title>test</title><link>https://xiaoying.org.cn/pages/bfbad8/</link><pubDate>Thu, 05 Mar 2026 18:19:22 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bfbad8/</guid><description>&lt;div class="code-toolbar mermaid-codeblock" data-mermaid-code="%% 用Mermaid复刻你图片中的目录结构
graph TD
 A[content/] --&amp;gt; B[docs/]
 A --&amp;gt; C[pages/]
 A --&amp;gt; D[posts/]
 B --&amp;gt; B1[sidebar.en.md]
 B --&amp;gt; B2[sidebar.zh.md]
 C --&amp;gt; C1[about.md]
 C --&amp;gt; C2[contact.md]
 D --&amp;gt; D1[2024-03-05-xxx.md]
 D --&amp;gt; D2[2024-03-06-yyy.md]"&gt;
 &lt;pre class="mermaid"&gt;%% 用Mermaid复刻你图片中的目录结构
graph TD
 A[content/] --&amp;gt; B[docs/]
 A --&amp;gt; C[pages/]
 A --&amp;gt; D[posts/]
 B --&amp;gt; B1[sidebar.en.md]
 B --&amp;gt; B2[sidebar.zh.md]
 C --&amp;gt; C1[about.md]
 C --&amp;gt; C2[contact.md]
 D --&amp;gt; D1[2024-03-05-xxx.md]
 D --&amp;gt; D2[2024-03-06-yyy.md]
 &lt;/pre&gt;
 &lt;div class="toolbar"&gt;
 &lt;div class="toolbar-item"&gt;
 &lt;button class="copy-to-clipboard-button mermaid-copy-btn" type="button" aria-label="copy" data-copy-state="copy" data-button-type="copy-to-clipboard"&gt;
 &lt;span&gt;&lt;/span&gt;
 &lt;/button&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="cb-language-label"&gt;
 &lt;span class="cb-dot red"&gt;&lt;/span&gt;
 &lt;span class="cb-dot yellow"&gt;&lt;/span&gt;
 &lt;span class="cb-dot green"&gt;&lt;/span&gt;
 &lt;span class="cb-lang-text"&gt;MERMAID&lt;/span&gt;
 &lt;/div&gt;
&lt;/div&gt;

&lt;div class="code-toolbar mermaid-codeblock" data-mermaid-code="graph TD
 A[Markdown内容] --&amp;gt; B[Hugo静态生成器]
 B --&amp;gt; C[Lotus Docs主题]
 B --&amp;gt; D[构建工具链]
 
 subgraph 构建工具链
 direction TB
 E[Node.js脚本] --&amp;gt; F[Yarn包管理器]
 F --&amp;gt; G[Scoop包管理器]
 end
 
 C --&amp;gt; H[静态HTML/CSS/JS]
 H --&amp;gt; I[部署平台]
 
 classDef subgraphStyle fill:#fff9c4,stroke:#fbc02d,stroke-width:2px
 class 构建工具链 subgraphStyle"&gt;
 &lt;pre class="mermaid"&gt;graph TD
 A[Markdown内容] --&amp;gt; B[Hugo静态生成器]
 B --&amp;gt; C[Lotus Docs主题]
 B --&amp;gt; D[构建工具链]
 
 subgraph 构建工具链
 direction TB
 E[Node.js脚本] --&amp;gt; F[Yarn包管理器]
 F --&amp;gt; G[Scoop包管理器]
 end
 
 C --&amp;gt; H[静态HTML/CSS/JS]
 H --&amp;gt; I[部署平台]
 
 classDef subgraphStyle fill:#fff9c4,stroke:#fbc02d,stroke-width:2px
 class 构建工具链 subgraphStyle
 &lt;/pre&gt;
 &lt;div class="toolbar"&gt;
 &lt;div class="toolbar-item"&gt;
 &lt;button class="copy-to-clipboard-button mermaid-copy-btn" type="button" aria-label="copy" data-copy-state="copy" data-button-type="copy-to-clipboard"&gt;
 &lt;span&gt;&lt;/span&gt;
 &lt;/button&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="cb-language-label"&gt;
 &lt;span class="cb-dot red"&gt;&lt;/span&gt;
 &lt;span class="cb-dot yellow"&gt;&lt;/span&gt;
 &lt;span class="cb-dot green"&gt;&lt;/span&gt;
 &lt;span class="cb-lang-text"&gt;MERMAID&lt;/span&gt;
 &lt;/div&gt;
&lt;/div&gt;

&lt;div class="code-toolbar mermaid-codeblock" data-mermaid-code="sequenceDiagram
 participant User
 participant Script as add-frontmatter.js
 participant FS as FileSystem
 participant Hugo

 User-&amp;gt;&amp;gt;Script: 执行 yarn run server
 Script-&amp;gt;&amp;gt;FS: 扫描content目录
 FS--&amp;gt;&amp;gt;Script: 返回.md文件列表
 loop 分析每个文件Front Matter
 Script-&amp;gt;&amp;gt;Script: 分析每个文件Front Matter
 end
 Script-&amp;gt;&amp;gt;FS: 补全缺失字段
 Script-&amp;gt;&amp;gt;Hugo: 启动本地服务器
 Hugo--&amp;gt;&amp;gt;User: 服务就绪 localhost:1313"&gt;
 &lt;pre class="mermaid"&gt;sequenceDiagram
 participant User
 participant Script as add-frontmatter.js
 participant FS as FileSystem
 participant Hugo

 User-&amp;gt;&amp;gt;Script: 执行 yarn run server
 Script-&amp;gt;&amp;gt;FS: 扫描content目录
 FS--&amp;gt;&amp;gt;Script: 返回.md文件列表
 loop 分析每个文件Front Matter
 Script-&amp;gt;&amp;gt;Script: 分析每个文件Front Matter
 end
 Script-&amp;gt;&amp;gt;FS: 补全缺失字段
 Script-&amp;gt;&amp;gt;Hugo: 启动本地服务器
 Hugo--&amp;gt;&amp;gt;User: 服务就绪 localhost:1313
 &lt;/pre&gt;
 &lt;div class="toolbar"&gt;
 &lt;div class="toolbar-item"&gt;
 &lt;button class="copy-to-clipboard-button mermaid-copy-btn" type="button" aria-label="copy" data-copy-state="copy" data-button-type="copy-to-clipboard"&gt;
 &lt;span&gt;&lt;/span&gt;
 &lt;/button&gt;
 &lt;/div&gt;
 &lt;/div&gt;
 &lt;div class="cb-language-label"&gt;
 &lt;span class="cb-dot red"&gt;&lt;/span&gt;
 &lt;span class="cb-dot yellow"&gt;&lt;/span&gt;
 &lt;span class="cb-dot green"&gt;&lt;/span&gt;
 &lt;span class="cb-lang-text"&gt;MERMAID&lt;/span&gt;
 &lt;/div&gt;
&lt;/div&gt;</description></item><item><title>asar解包与打包</title><link>https://xiaoying.org.cn/pages/629249/</link><pubDate>Mon, 02 Mar 2026 21:03:43 +0000</pubDate><guid>https://xiaoying.org.cn/pages/629249/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;适用于 Electron 应用 &lt;code&gt;app.asar&lt;/code&gt; 文件的解压与重新打包&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="heading"&gt;安装依赖 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-asar-"&gt;安装 asar 工具 &lt;a href="#-asar-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2a1fd7a" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install -g @electron/asar&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-1"&gt;验证是否安装成功 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c44d9e7" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;asar --version&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="-asar--1"&gt;解压 asar 文件 &lt;a href="#-asar--1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b69f66f" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 通用命令
asar extract 文件名.asar 解压到的文件夹

# 示例（解压 app.asar 到 app_extracted 目录）
asar extract app.asar ./app_extracted&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;仅查看文件列表 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="427ae05" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;asar list app.asar&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-3"&gt;只提取单个文件 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2c99caf" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;asar extract-file app.asar main.js&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="-asar"&gt;重新打包为 asar &lt;a href="#-asar" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="01eb0df" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 通用命令
asar pack 源文件夹 输出文件名.asar

# 示例（把修改后的文件夹打包回 app.asar）
asar pack ./app_extracted app.asar&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-4"&gt;打包时排除目录（推荐） &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;排除 &lt;code&gt;node_modules&lt;/code&gt; 等不需要打进 asar 的文件：&lt;/p&gt;</description></item><item><title>代码生成器</title><link>https://xiaoying.org.cn/pages/ddce09/</link><pubDate>Tue, 15 Apr 2025 17:28:08 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ddce09/</guid><description>&lt;h1 id="spring-boot-"&gt;Spring Boot 代码生成器 &lt;a href="#spring-boot-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;基于Spring Boot + Velocity的代码生成器，用于快速生成项目代码，提高开发效率。&lt;/p&gt;
&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这是一个基于Spring Boot 的代码生成器，支持通过数据库表结构自动生成Controller、Service、Mapper、Entity等相关代码，大幅提高开发效率。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;特性 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;使用Velocity模板引擎生成代码&lt;/li&gt;
&lt;li&gt;支持自定义模板&lt;/li&gt;
&lt;li&gt;支持多种代码生成模式&lt;/li&gt;
&lt;li&gt;支持字段级别的配置（表单显示、列表显示、查询条件等）&lt;/li&gt;
&lt;li&gt;支持代码预览和下载&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;快速开始 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="_1-"&gt;_1. 基本配置 &lt;a href="#_1-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="_11-"&gt;_1.1 引入依赖 &lt;a href="#_11-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;&lt;p&gt;依赖可能非最新版本，请前往maven获取最新版本&lt;/p&gt;
&lt;p&gt;&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/spring-boot-starter-codegen" rel="external" target="_blank"&gt;Spring Boot 2&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;地址&lt;/p&gt;</description></item><item><title>InputTag</title><link>https://xiaoying.org.cn/pages/74f429/</link><pubDate>Fri, 04 Apr 2025 06:01:30 +0000</pubDate><guid>https://xiaoying.org.cn/pages/74f429/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;基于&lt;code&gt;el-tag&lt;/code&gt;的封装&lt;/p&gt;
&lt;h2 id="heading-1"&gt;可选参数 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="65013fd" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;defineProps({
 config: {
 type: Object as () =&amp;gt; {
 buttonAttrs: Record&amp;lt;string, any&amp;gt;; 
 inputAttrs: Record&amp;lt;string, any&amp;gt;;
 tagAttrs: Record&amp;lt;string, any&amp;gt;;
 },
 default: () =&amp;gt; ({
 buttonAttrs: {}, //可配置 el-button 的所有 props 和自定义属性
 inputAttrs: {}, //可配置 el-input 的所有 props 和自定义属性：
 tagAttrs: {}, //可配置 el-tag 的所有 props 和自定义属性：
 }),
 },
});&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;使用 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2b8bae1" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
	import InputTag from &amp;#34;liyao-vue-common&amp;#34;
 
 const attr = {
 buttonAttrs: {
 btnText: &amp;#34;新增标签&amp;#34;
 }

}

&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;InputTag :config=&amp;#34;attr&amp;#34;&amp;gt;&amp;lt;/InputTag&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>EasyExcel之Excel导入导出</title><link>https://xiaoying.org.cn/pages/978f7f/</link><pubDate>Mon, 06 Nov 2023 13:42:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/978f7f/</guid><description>&lt;h2 id="heading"&gt;基本导入导出 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="pom"&gt;Pom依赖 &lt;a href="#pom" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;::: info 提示&lt;/p&gt;
&lt;p&gt;图片的绿色小字就是最新版本： &lt;a href="https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel" rel="external" target="_blank"&gt;










 &lt;img class="post-image zoomable" src="https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=1600" srcset="
 https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=480 480w,
 https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=768 768w,
 https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=1024 1024w,
 https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=1600 1600w,
 https://maven-badges.herokuapp.com/maven-central/com.alibaba/easyexcel/badge.svg?w=2400 2400w
 " sizes="100vw" alt="Maven central" loading="lazy"&gt;


&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;如果看不到图片则直接打开：&lt;a href="https://mvnrepository.com/artifact/com.alibaba/easyexcel" rel="external" target="_blank"&gt;https://mvnrepository.com/artifact/com.alibaba/easyexcel&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>EasyExcel具体使用</title><link>https://xiaoying.org.cn/pages/ec032e/</link><pubDate>Thu, 09 Nov 2023 10:16:01 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ec032e/</guid><description>&lt;h2 id="uploaddatadto"&gt;UploadData（dto类） &lt;a href="#uploaddatadto" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="89c0fa4" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@EqualsAndHashCode(callSuper = false)
@Data
public class UploadData extends PageRequest implements Serializable {

 /**
 * 姓名
 */
 @ExcelProperty(&amp;#34;姓名&amp;#34;)
 private String name;

 /**
 * 年龄
 */
 @ExcelProperty(&amp;#34;年龄&amp;#34;)
 private Integer age;

 /**
 * 手机号
 */
 @ExcelProperty(&amp;#34;手机号&amp;#34;)
 private Long phone;

 /**
 * 工资
 */
 @ExcelProperty(&amp;#34;工资&amp;#34;)
 private Long salary;

 /**
 * 生日
 */
 @JsonFormat(timezone = &amp;#34;GMT&amp;#43;8&amp;#34;, pattern = &amp;#34;yyyy-MM-dd&amp;#34;)
 @DateTimeFormat(Pattern = &amp;#34;yyyy-MM-dd&amp;#34;)
 @ExcelProperty(&amp;#34;生日&amp;#34;)
 private Date birthday;

 private static final long serialVersionUID = 1L;

 public static UploadData convertToDto(Excel excel) {
 UploadData uploadData = new UploadData();
 uploadData.setName(excel.getName());
 uploadData.setAge(excel.getAge());
 uploadData.setPhone(excel.getPhone());
 uploadData.setSalary(excel.getSalary());
 uploadData.setBirthday(excel.getBirthday());
 return uploadData;
 }

}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="dateconverter"&gt;DateConverter（日期格式转换） &lt;a href="#dateconverter" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2703060" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;public class DateConverter implements Converter&amp;lt;Date&amp;gt; {

 private static final String PATTERN_YYYY_MM_DD = &amp;#34;yyyy-MM-dd&amp;#34;;

 @Override
 public Class&amp;lt;?&amp;gt; supportJavaTypeKey() {
 return Converter.super.supportJavaTypeKey();
 }

 @Override
 public CellDataTypeEnum supportExcelTypeKey() {
 return Converter.super.supportExcelTypeKey();
 }

 @Override
 public WriteCellData&amp;lt;?&amp;gt; convertToExcelData(Date value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
 SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_YYYY_MM_DD);
 String dateValue = sdf.format(value);
 return new WriteCellData&amp;lt;&amp;gt;(dateValue);
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="uploaddatavovo"&gt;UploadDataVO（VO类） &lt;a href="#uploaddatavovo" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="21c9cef" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Data
public class UploadDataVO implements Serializable {

 /**
 * 姓名
 */
 @ColumnWidth(15)
 @ExcelProperty(value = &amp;#34;姓名&amp;#34;, index = 0)
 private String name;

 /**
 * 年龄
 */
 @ColumnWidth(10)
 @ExcelProperty(value = &amp;#34;年龄&amp;#34;, index = 1)
 private Integer age;

 /**
 * 手机号
 */
 @ColumnWidth(25)
 @ExcelProperty(value = &amp;#34;手机号&amp;#34;, index = 2)
 private Long phone;

 /**
 * 工资
 */
 @ColumnWidth(20)
 @ExcelProperty(value = &amp;#34;工资&amp;#34;, index = 3)
 private Long salary;

 /**
 * 生日
 */
 @ColumnWidth(30)
 @JsonFormat(timezone = &amp;#34;GMT&amp;#43;8&amp;#34;, pattern = &amp;#34;yyyy-MM-dd&amp;#34;)
 @ExcelProperty(value = &amp;#34;生日&amp;#34;, index = 4, converter = DateConverter.class)
 private Date birthday;

 private static final long serialVersionUID = 1L;

 public static UploadDataVO convertToVO(Excel excel) {
 UploadDataVO uploadData = new UploadDataVO();
 uploadData.setName(excel.getName());
 uploadData.setAge(excel.getAge());
 uploadData.setPhone(excel.getPhone());
 uploadData.setSalary(excel.getSalary());
 uploadData.setBirthday(excel.getBirthday());
 return uploadData;
 }

}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="uploaddaodao"&gt;UploadDAO（DAO层） &lt;a href="#uploaddaodao" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0e0f6b2" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Repository
public class UploadDAO {

 @Resource
 private ExcelService excelService;

 public void save(List&amp;lt;Excel&amp;gt; list) {
 excelService.saveBatch(list);
 }

 public List&amp;lt;Excel&amp;gt; list(Wrapper&amp;lt;Excel&amp;gt; list) {

 return excelService.list(list);
 }

 public List&amp;lt;Excel&amp;gt; convertToEntityList(List&amp;lt;UploadData&amp;gt; uploadDataList) {
 List&amp;lt;Excel&amp;gt; excelList = new ArrayList&amp;lt;&amp;gt;();

 for (UploadData uploadData : uploadDataList) {
 Excel excel = convertToEntity(uploadData);
 excelList.add(excel);
 }

 return excelList;
 }

 public List&amp;lt;UploadDataVO&amp;gt; convertToDtoList(List&amp;lt;Excel&amp;gt; uploadDataList) {
 List&amp;lt;UploadDataVO&amp;gt; excelList = new ArrayList&amp;lt;&amp;gt;();

 for (Excel uploadData : uploadDataList) {
 UploadDataVO excel = UploadDataVO.convertToVO(uploadData);
 excelList.add(excel);
 }

 return excelList;
 }

 public Excel convertToEntity(UploadData uploadData) {
 Excel excel = new Excel();
 excel.setName(uploadData.getName());
 excel.setAge(uploadData.getAge());
 excel.setPhone(uploadData.getPhone());
 excel.setSalary(uploadData.getSalary());
 excel.setBirthday(uploadData.getBirthday());
 return excel;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="uploaddatalistener"&gt;UploadDataListener（监听器） &lt;a href="#uploaddatalistener" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5d8e8dc" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 * 模板的读取类
 *
 * @author Jiaju Zhuang
 */
// 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class UploadDataListener implements ReadListener&amp;lt;UploadData&amp;gt; {
 /**
 * 每隔5条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
 */
 private static final int BATCH_COUNT = 100;
 private List&amp;lt;UploadData&amp;gt; cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

 @Resource
 private UploadDAO uploadDAO;

 @Resource
 private ExcelMapper excelMapper;

 public UploadDataListener() {
 // 这里是demo，所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
 uploadDAO = new UploadDAO();
 }

 /**
 * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
 *
 * @param uploadDAO
 */
 public UploadDataListener(UploadDAO uploadDAO) {
 this.uploadDAO = uploadDAO;
 }

 /**
 * 这个每一条数据解析都会来调用
 *
 * @param data one row value. It is same as {@link AnalysisContext#readRowHolder()}
 * @param context
 */
 @Override
 public void invoke(UploadData data, AnalysisContext context) {
 log.info(&amp;#34;解析到一条数据:{}&amp;#34;, JSON.toJSONString(data));
 cachedDataList.add(data);
 // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
 if (cachedDataList.size() &amp;gt;= BATCH_COUNT) {
 saveData();
 // 存储完成清理 list
 cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
 }
 }

 /**
 * 异常方法 (类型转换异常也会执行此方法) （读取一行抛出异常也会执行此方法)
 *
 * @param exception
 * @param context
 * @throws Exception
 */
 @Override
 public void onException(Exception exception, AnalysisContext context) {
 // 如果是某一个单元格的转换异常 能获取到具体行号
 // 如果要获取头的信息 配合invokeHeadMap使用
 if (exception instanceof ExcelDataConvertException) {
 ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
 log.error(&amp;#34;第{}行，第{}列解析异常，数据为:{}&amp;#34;, excelDataConvertException.getRowIndex(),
 excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
 throw new BusinessException(ErrorCode.OPERATION_ERROR,&amp;#34;第&amp;#34;&amp;#43;excelDataConvertException.getRowIndex()&amp;#43;&amp;#34;行&amp;#34; &amp;#43; &amp;#34;，第&amp;#34; &amp;#43; (excelDataConvertException.getColumnIndex() &amp;#43; 1) &amp;#43; &amp;#34;列读取错误&amp;#34;);
 }
 }

 /**
 * 所有数据解析完成了 都会来调用
 *
 * @param context
 */
 @Override
 public void doAfterAllAnalysed(AnalysisContext context) {
 // 这里也要保存数据，确保最后遗留的数据也存储到数据库
 saveData();
 log.info(&amp;#34;所有数据解析完成！&amp;#34;);
 }

 /**
 * 返回数据
 *
 * @return 返回读取的数据集合
 **/
 public List&amp;lt;UploadData&amp;gt; listData() {
 return cachedDataList;
 }

 /**
 * 加上存储数据库
 */
 private void saveData() {
 log.info(&amp;#34;{}条数据，开始存储数据库！&amp;#34;, cachedDataList.size());

 // 检查是否重复导入
 QueryWrapper&amp;lt;Excel&amp;gt; queryWrapper = new QueryWrapper&amp;lt;&amp;gt;();
 queryWrapper.in(&amp;#34;phone&amp;#34;, cachedDataList.stream().map(UploadData::getPhone).toArray());
 List&amp;lt;Excel&amp;gt; databaseData = uploadDAO.list(queryWrapper);

 for (UploadData excelRecord : cachedDataList) {
 for (Excel dbRecord : databaseData) {
 if (excelRecord.getPhone().equals(dbRecord.getPhone()) &amp;amp;&amp;amp; excelRecord.getName().equals(dbRecord.getName())) {
 throw new BusinessException(ErrorCode.OPERATION_ERROR, &amp;#34;重复导入: &amp;#34; &amp;#43; excelRecord);
 }
 }
 }

 // 保存到数据库
 List&amp;lt;Excel&amp;gt; list = uploadDAO.convertToEntityList(cachedDataList);
 uploadDAO.save(list);
 log.info(&amp;#34;存储数据库成功！&amp;#34;);
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="excelservice"&gt;ExcelService &lt;a href="#excelservice" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a785a1d" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;public interface ExcelService extends IService&amp;lt;Excel&amp;gt; {

 /**
 * 分页获取帖子封装
 *
 * @param excelPage
 * @param request
 * @return
 */
 Page&amp;lt;UploadData&amp;gt; getExcelPage(Page&amp;lt;Excel&amp;gt; excelPage, HttpServletRequest request);

 /**
 * 获取查询条件
 *
 * @param uploadData
 * @return
 */
 QueryWrapper&amp;lt;Excel&amp;gt; getQueryWrapper(UploadData uploadData);

}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="excelserviceimpl"&gt;ExcelServiceImpl &lt;a href="#excelserviceimpl" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b4f456a" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;@Service
public class ExcelServiceImpl extends ServiceImpl&amp;lt;ExcelMapper, Excel&amp;gt;
 implements ExcelService{

 /**
 * 分页获取帖子封装
 *
 * @param excelPage
 * @param request
 * @return
 */
 @Override
 public Page&amp;lt;UploadData&amp;gt; getExcelPage(Page&amp;lt;Excel&amp;gt; excelPage, HttpServletRequest request) {
 List&amp;lt;Excel&amp;gt; excellists = excelPage.getRecords();
 Page&amp;lt;UploadData&amp;gt; fileListVOPage = new Page&amp;lt;&amp;gt;(excelPage.getCurrent(), excelPage.getSize(),
 excelPage.getTotal());
 List&amp;lt;UploadData&amp;gt; fileListVOList = excellists.stream().map(fileList -&amp;gt; {
 UploadData fileListVO = UploadData.convertToDto(fileList);
 return fileListVO;
 }).collect(Collectors.toList());
 fileListVOPage.setRecords(fileListVOList);
 return fileListVOPage;
 }

 /**
 * 获取查询条件
 *
 * @param uploadData
 * @return
 */
 @Override
 public QueryWrapper&amp;lt;Excel&amp;gt; getQueryWrapper(UploadData uploadData) {

 QueryWrapper&amp;lt;Excel&amp;gt; wrapper = new QueryWrapper&amp;lt;&amp;gt;();
 if (uploadData == null) {
 return wrapper;
 }

 String name = uploadData.getName();
 Integer age = uploadData.getAge();
 Long phone = uploadData.getPhone();
 Long salary = uploadData.getSalary();


 wrapper.like(StringUtils.isNotBlank(name),&amp;#34;name&amp;#34;,name);
 wrapper.like(ObjectUtils.isNotEmpty(age),&amp;#34;age&amp;#34;,age);
 wrapper.like(ObjectUtils.isNotEmpty(phone),&amp;#34;phone&amp;#34;,phone);
 wrapper.like(ObjectUtils.isNotEmpty(salary),&amp;#34;salary&amp;#34;,salary);

 return wrapper;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="excelcontroller"&gt;ExcelController &lt;a href="#excelcontroller" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4650b3e" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 * Excel文件接口
 *
 */
@RestController
@RequestMapping(&amp;#34;/excel&amp;#34;)
@Slf4j
@Tag(name = &amp;#34;ExcelController&amp;#34;)
public class ExcelController {

 @Resource
 private UserService userService;

 @Resource
 private UploadDAO uploadDAO;

 @Resource
 private ExcelService excelService;

 /**
 * 文件上传
 * &amp;lt;p&amp;gt;
 * 1. 创建excel对应的实体对象 参照{@link UploadData}
 * &amp;lt;p&amp;gt;
 * 2. 由于默认一行行的读取excel，所以需要创建excel一行一行的回调监听器，参照{@link UploadDataListener}
 * &amp;lt;p&amp;gt;
 * 3. 直接读即可
 */
 @PostMapping(&amp;#34;upload&amp;#34;)
 @Operation(summary = &amp;#34;easyExcel上传&amp;#34;)
 @ResponseBody
 public BaseResponse&amp;lt;List&amp;lt;UploadData&amp;gt;&amp;gt; upload(MultipartFile file, HttpServletRequest request) throws IOException {

 userService.getLoginUser(request);

 UploadDataListener uploadListener = new UploadDataListener(uploadDAO);
 EasyExcel.read(file.getInputStream(), UploadData.class, uploadListener).sheet().doRead();
 return ResultUtils.success(uploadListener.listData());
 }

 /**
 * 文件下载（失败了会返回一个有部分数据的Excel）
 * &amp;lt;p&amp;gt;
 * 1. 创建excel对应的实体对象 参照{@link UploadData}
 * &amp;lt;p&amp;gt;
 * 2. 设置返回的 参数
 * &amp;lt;p&amp;gt;
 * 3. 直接写，这里注意，finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
 */
 @GetMapping(&amp;#34;download&amp;#34;)
 @Operation(summary = &amp;#34;easyExcel下载&amp;#34;)
 public void download(HttpServletResponse response, HttpServletRequest request) throws IOException {

 userService.getLoginUser(request);

 // 这里注意 有同学反应使用swagger 会导致各种问题，请直接用浏览器或者用postman
 response.setContentType(&amp;#34;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet&amp;#34;);
 response.setCharacterEncoding(&amp;#34;utf-8&amp;#34;);
 // 这里URLEncoder.encode可以防止中文乱码
 Date now = new Date();
 long timestamp = now.getTime();
 String uuid = RandomStringUtils.randomAlphanumeric(8);
 String filename = uuid &amp;#43; &amp;#34;-&amp;#34; &amp;#43; timestamp &amp;#43; &amp;#34;-模板&amp;#34;;
 String fileName = URLEncoder.encode(filename, &amp;#34;UTF-8&amp;#34;).replaceAll(&amp;#34;\\&amp;#43;&amp;#34;, &amp;#34;%20&amp;#34;);
 response.setHeader(&amp;#34;Content-disposition&amp;#34;, &amp;#34;attachment;filename*=utf-8&amp;#39;&amp;#39;&amp;#34; &amp;#43; fileName &amp;#43; &amp;#34;.xlsx&amp;#34;);

 List&amp;lt;Excel&amp;gt; data = excelService.list();
 List&amp;lt;UploadDataVO&amp;gt; list = uploadDAO.convertToDtoList(data);

 // 头的策略
 WriteCellStyle headWriteCellStyle = new WriteCellStyle();
 // 背景设置为红色
 WriteFont headWriteFont = new WriteFont();
 headWriteFont.setFontHeightInPoints((short)20);
 headWriteCellStyle.setWriteFont(headWriteFont);
 headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);


 // 内容的策略
 WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
 WriteFont contentWriteFont = new WriteFont();
 //contentWriteFont.setFontName(&amp;#34;微软雅黑&amp;#34;);
 contentWriteFont.setFontHeightInPoints((short) 16);
 contentWriteFont.setColor(IndexedColors.BLACK.getIndex());
 // 字体大小
 contentWriteCellStyle.setWriteFont(contentWriteFont);

 contentWriteCellStyle.setBorderLeft(BorderStyle.THIN); // 左边框线
 contentWriteCellStyle.setBorderRight(BorderStyle.THIN); // 右边框线
 contentWriteCellStyle.setBorderTop(BorderStyle.THIN); // 上边框线
 contentWriteCellStyle.setBorderBottom(BorderStyle.THIN); // 下边框线
 contentWriteCellStyle.setWrapped(false); //设置自动换行;
 contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);//设置水平对齐的样式为居中对齐;
 contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); //设置垂直对齐的样式为居中对齐;
 contentWriteCellStyle.setShrinkToFit(true);//设置文本收缩至合适

 // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
 HorizontalCellStyleStrategy horizontalCellStyleStrategy =
 new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);

 EasyExcel.write(response.getOutputStream(), UploadDataVO.class).registerWriteHandler(horizontalCellStyleStrategy).sheet(&amp;#34;sheet1&amp;#34;).doWrite(list);
 }

 /**
 * 分页获取列表（封装类）
 *
 * @param uploadData
 * @param request
 * @return
 */
 @Operation(summary = &amp;#34;获取Excel文件列表&amp;#34;)
 @PostMapping(&amp;#34;/list/page&amp;#34;)
 public BaseResponse&amp;lt;Page&amp;lt;UploadData&amp;gt;&amp;gt; listExcelList(@RequestBody UploadData uploadData,
 HttpServletRequest request) {
 long current = uploadData.getCurrent();
 long size = uploadData.getPageSize();

 userService.getLoginUser(request);

 ThrowUtils.throwIf(size &amp;gt; 80, ErrorCode.PARAMS_ERROR);
 Page&amp;lt;Excel&amp;gt; postPage = excelService.page(new Page&amp;lt;&amp;gt;(current, size),
 excelService.getQueryWrapper(uploadData));
 return ResultUtils.success(excelService.getExcelPage(postPage, request));
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>FreeMarker 模板引擎入门</title><link>https://xiaoying.org.cn/pages/aad4a8/</link><pubDate>Sun, 19 Nov 2023 13:23:33 +0000</pubDate><guid>https://xiaoying.org.cn/pages/aad4a8/</guid><description>&lt;h2 id="heading"&gt;一、简述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;hr&gt;

 &lt;blockquote&gt;
 &lt;p&gt;在线文档：&lt;a href="http://freemarker.foofun.cn/" rel="external" target="_blank"&gt;http://freemarker.foofun.cn/&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;FreeMarker 也是一款模板引擎技术，它是一种基于模板和要改变的数据，并用来生成输出文本(HTML网页，电子邮件，配置文件，源代码等)的通用工具。当然它也是一个Java类库，可以将之作为一个普通的组件嵌入到我们的产品中。&lt;/p&gt;
&lt;p&gt;FreeMarker被设计用来生成HTML Web页面，特别是基于&lt;a href="https://so.csdn.net/so/search?q=MVC模式&amp;spm=1001.2101.3001.7020" rel="external" target="_blank"&gt;MVC模式&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;的应用程序，将视图从业务逻辑中抽离出来，业务中不再包括视图的展示，而是将视图交给FreeMarker来输出。虽然FreeMarker具有一些编程的能力，但通常先让Java程序准备要显示的数据，然后再用FreeMarker生成具体页面。











 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202311221501752.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202311221501752.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202311221501752.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202311221501752.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202311221501752.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202311221501752.png?w=2400 2400w
 " sizes="100vw" alt="1" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>FreeMarker生成文件及WEB使用</title><link>https://xiaoying.org.cn/pages/ae6bd1/</link><pubDate>Thu, 23 Nov 2023 15:20:08 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ae6bd1/</guid><description>&lt;h2 id="heading"&gt;生成本地文件 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;创建一个Configuration对象，直接new一个对象。构造方法的参数就是freemarker对于的版本号。&lt;/li&gt;
&lt;li&gt;设置模板文件所在的路径。&lt;/li&gt;
&lt;li&gt;设置模板文件使用的字符集。一般就是utf-8.&lt;/li&gt;
&lt;li&gt;加载一个模板，创建一个模板对象。&lt;/li&gt;
&lt;li&gt;创建一个模板使用的数据集，可以是pojo也可以是map。一般是Map。&lt;/li&gt;
&lt;li&gt;创建一个Writer对象，一般创建一FileWriter对象，指定生成的文件名。&lt;/li&gt;
&lt;li&gt;调用模板对象的process方法输出文件。&lt;/li&gt;
&lt;li&gt;关闭流.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例模板index.ftl如下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6a331f5" class="language-velocity wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&amp;#34;&amp;#34;&amp;gt;
&amp;lt;head&amp;gt;
 &amp;lt;meta charset=&amp;#34;utf-8&amp;#34;&amp;gt;
 &amp;lt;title&amp;gt;Hello World!&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;b&amp;gt;普通文本 String 展示：&amp;lt;/b&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
Hello ${name} &amp;lt;br&amp;gt;
&amp;lt;hr&amp;gt;
&amp;lt;b&amp;gt;对象Student中的数据展示：&amp;lt;/b&amp;gt;&amp;lt;br/&amp;gt;
姓名：${stu.name}&amp;lt;br/&amp;gt;
年龄：${stu.age}
&amp;lt;hr&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;业务层代码如下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ff8cbf7" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 * FreeMarker一般的使用方式 示例
 */
@SpringBootTest
public class NormalTests {

 @Test
 public void test() throws IOException, TemplateException {

 String templateDir = String templateDir = &amp;#34;src/main/resources/templates/&amp;#34;;

 // -&amp;gt; 获取FreeMarker配置实例
 Configuration conf = new Configuration(Configuration.VERSION_2_3_32);

 // -&amp;gt; 指定模板文件所在文件夹
 // 直接指明文件夹路径的方式
 conf.setDirectoryForTemplateLoading(new File(templateDir));
 // 通过类加载器，使用相对路径的方式
 // conf.setClassLoaderForTemplateLoading(ClassLoader.getSystemClassLoader(), &amp;#34;/templates/&amp;#34;);

 // -&amp;gt; 设置编码(注:如果不设置或设置错了此项的话，那么加载模板的时候，可能导致中文乱码)
 conf.setDefaultEncoding(&amp;#34;utf-8&amp;#34;);

 // -&amp;gt; 获取ftl模板
 Template template = conf.getTemplate(&amp;#34;index.ftl&amp;#34;);

 // -&amp;gt; 准备数据数据
 Map&amp;lt;String, Object&amp;gt; root = new HashMap&amp;lt;&amp;gt;(8);
 // 注意:因为freemarker模板会试着解析key,所以key命名时不要有敏感词汇；如:这里key取的是【root-key】的话，那么就会出错
 Map&amp;lt;String, Object&amp;gt; root = new HashMap&amp;lt;&amp;gt;(8);
 root.put(&amp;#34;name&amp;#34;,&amp;#34;小舞&amp;#34;);
 //实体类
 Student student = new Student();
 student.setAge(22);
 student.setName(&amp;#34;张三&amp;#34;);
 student.setBirthday(new Date());
 root.put(&amp;#34;stu&amp;#34;,student);

 // -&amp;gt; 准备输出流
 // 此方式可能导致输出时中文乱码
 // Writer out = new FileWriter(new File(&amp;#34;E:/demo/templates/normal.html&amp;#34;));
 // 此方式可保证输出时中文不乱码
 Writer out =
 new BufferedWriter(new OutputStreamWriter(Files.newOutputStream(new File(templateDir &amp;#43; &amp;#34;index.html&amp;#34;).toPath()),
 StandardCharsets.UTF_8));
 
 // -&amp;gt; 数据 &amp;#43; 输出流 = 生成的文件
 template.process(root, out);

 // -&amp;gt; 释放资源
 out.flush();
 out.close();
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="webfreemarker"&gt;通过WEB使用FreeMarker的方式 &lt;a href="#webfreemarker" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;::: info 关键点说明&lt;/p&gt;</description></item><item><title>TrueLicense 创建及安装证书</title><link>https://xiaoying.org.cn/pages/61f6dc/</link><pubDate>Fri, 25 Oct 2024 17:23:15 +0000</pubDate><guid>https://xiaoying.org.cn/pages/61f6dc/</guid><description>&lt;h2 id="-keytool-"&gt;使用 keytool 生成公私钥证书库 &lt;a href="#-keytool-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;例如：私钥库密码为 priwd123456，公钥库密码为 pubwd123456，生成步骤如下：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c93d5e1" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 生成私钥库
# validity：私钥的有效期（天）
# alias：私钥别称
# keystore：私钥库文件名称（生成在当前目录）
# storepass：私钥库密码（获取 keystore 信息所需的密码，密钥库口令）
# keypass：别名条目的密码(密钥口令)
keytool -genkeypair -keysize 1024 -validity 3650 -alias &amp;#34;privateKey&amp;#34; -keystore &amp;#34;privateKeys.keystore&amp;#34; -storepass &amp;#34;pubwd123456&amp;#34; -keypass &amp;#34;priwd123456&amp;#34; -dname &amp;#34;CN=localhost, OU=localhost, O=localhost, L=SH, ST=SH, C=CN&amp;#34;

# 把私钥库内的公钥导出到一个文件当中
# alias：私钥别称
# keystore：私钥库的名称（在当前目录查找）
# storepass：私钥库的密码
# file：证书名称
keytool -exportcert -alias &amp;#34;privateKey&amp;#34; -keystore &amp;#34;privateKeys.keystore&amp;#34; -storepass &amp;#34;pubwd123456&amp;#34; -file &amp;#34;certfile.cer&amp;#34;

# 再把这个证书文件导入到公钥库，certfile.cer 没用了可以删掉了
# alias：公钥名称
# file：证书名称
# keystore：公钥文件名称
# storepass：公钥库密码
keytool -import -alias &amp;#34;publicCert&amp;#34; -file &amp;#34;certfile.cer&amp;#34; -keystore &amp;#34;publicCerts.keystore&amp;#34; -storepass &amp;#34;pubwd123456&amp;#34;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;项目配置 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="81db985" class="language-yml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;server:
 port: 8080
# License 相关配置
license:
 # 主题
 subject: license_demo
 # 公钥别称
 publicAlias: publicCert
 # 访问公钥的密码
 storePass: pubwd123456
 # license 位置
 licensePath: E:/licenseTest/license.lic
 # licensePath: /root/license-test/license.lic
 # 公钥位置
 publicKeysStorePath: E:/licenseTest/publicCerts.keystore
 # publicKeysStorePath: /root/license-test/publicCerts.keystore&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;使用方式 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;全局拦截过滤器 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cfd9c2f" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;public class CustomFilter extends OncePerRequestFilter {

 @Resource
 private LicenseVerify licenseVerify;
 
 @Resource
 private UserService userService;

 // 指定允许通过的接口路径
 private static final List&amp;lt;String&amp;gt; ALLOWED_PATHS = Arrays.asList(
 // 添加允许通过的接口路径
 //swagger接口
 &amp;#34;/api/webjars/**&amp;#34;,
 &amp;#34;/api/doc.html&amp;#34;,
 &amp;#34;/api/swagger-resources/**&amp;#34;,
 &amp;#34;/api/v3/api-docs/**&amp;#34;,
 &amp;#34;/api/swagger-ui/**&amp;#34;,
 &amp;#34;/api/swagger-ui.html&amp;#34;,
 &amp;#34;/api/ws/**&amp;#34;,
 &amp;#34;/api/ws-app/**&amp;#34;,
 &amp;#34;/api/v3/api-docs/swagger-config&amp;#34;,
 &amp;#34;/api/v3/api-docs/default&amp;#34;,
 // 用户接口
 &amp;#34;/api/user/login&amp;#34;,
 &amp;#34;/api/user/register&amp;#34;,
 &amp;#34;/api/user/logout&amp;#34;,
 &amp;#34;/api/user/getInfo&amp;#34;,
 &amp;#34;/api/user/login/wx_open&amp;#34;,
 &amp;#34;/api/user/refresh&amp;#34;,
 // 验证码接口
 &amp;#34;/api/captcha/get&amp;#34;,
 &amp;#34;/api/captcha/check&amp;#34;,
 //授权文件接口
 &amp;#34;/api/license/upload&amp;#34;,
 &amp;#34;/api/license/multipartUpload&amp;#34;,
 &amp;#34;/api/license/generateLicense&amp;#34;,
 &amp;#34;/api/license/getServerInfos&amp;#34;
 );

 private final AntPathMatcher antPathMatcher = new AntPathMatcher();

 @Override
 protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response,
 @NotNull FilterChain filterChain) throws ServletException, IOException {

 if (request.getMethod().equals(&amp;#34;OPTIONS&amp;#34;)) {
 // 如果是预检请求，直接放行
 filterChain.doFilter(request, response);
 return;
 }

 String requestURI = request.getRequestURI();

 // 检查请求的URL是否在允许列表中
 if (ALLOWED_PATHS.stream().anyMatch(path -&amp;gt; antPathMatcher.match(path, requestURI))) {
 // 如果在允许列表中，则继续处理请求
 filterChain.doFilter(request, response);
 } else {

 try {

 boolean isLogin = userService.isLogin(request);
 if (!isLogin) {
 extracted(response, ErrorCode.NOT_LOGIN_ERROR);
 return;
 }

 licenseVerify.installLicense();
 filterChain.doFilter(request, response);

 } catch (Exception e) {

 // 处理 installLicense() 失败的情况
 extracted(response, ErrorCode.LICENCE_ERROR);

 }
 }
 }

 private static void extracted(@NotNull HttpServletResponse response, ErrorCode errorCode) throws IOException {
 response.setContentType(&amp;#34;application/json&amp;#34;);
 response.setCharacterEncoding(&amp;#34;UTF-8&amp;#34;);

 // 构建 JSON 响应
 JSONObject jsonResponse = new JSONObject();
 jsonResponse.put(&amp;#34;code&amp;#34;, errorCode.getCode());
 jsonResponse.put(&amp;#34;message&amp;#34;, errorCode.getMessage());

 // 写入响应体
 PrintWriter out = response.getWriter();
 out.print(jsonResponse);
 out.flush();
 out.close();
 }


}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;跨域配置中使用&lt;/p&gt;</description></item><item><title>登录后重定向到原先路由</title><link>https://xiaoying.org.cn/pages/5b5ff1/</link><pubDate>Fri, 19 Jan 2024 14:25:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/5b5ff1/</guid><description>&lt;h2 id="vue"&gt;编写对应vue文件 &lt;a href="#vue" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="loginvue"&gt;login.vue &lt;a href="#loginvue" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="edd5112" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
... // 登录组件
&amp;lt;/template&amp;gt;

&amp;lt;script lang=&amp;#34;ts&amp;#34; setup&amp;gt;
import { reactive, ref } from &amp;#39;vue&amp;#39;;
import { message } from &amp;#39;ant-design-vue&amp;#39;;
import { postUserLogin } from &amp;#39;@/api/controller/UserController&amp;#39;;
import router from &amp;#39;@/router&amp;#39;;
import { LocationQuery, LocationQueryValue, useRoute } from &amp;#34;vue-router&amp;#34;;
 
const route = useRoute()

/**
 * 按钮loading
 */
const loading = ref&amp;lt;boolean&amp;gt;(false);

const formState = reactive&amp;lt;UserLoginRequest&amp;gt;({
 userAccount: &amp;#39;&amp;#39;,
 userPassword: &amp;#39;&amp;#39;,
});


/**
 * 登录
 */
 function onSubmit() {
	loading.value = true;
	 postUserLogin(formState).then((res:any) =&amp;gt; {
		 if (res.code === 0) {
			 localStorage.setItem(&amp;#39;token&amp;#39;, res.data.token);
			 const query: LocationQuery = route.query;
			const redirect = (query.redirect as LocationQueryValue) ?? &amp;#34;/&amp;#34;;
			const otherQueryParams = Object.keys(query).reduce(
				(acc: any, cur: string) =&amp;gt; {
					if (cur !== &amp;#34;redirect&amp;#34;) {
						acc[cur] = query[cur];
					}
					return acc;
				},
				{}
			);

			 router.push({ path: redirect, query: otherQueryParams }).then(() =&amp;gt; { 
					message.success(&amp;#39;登录成功&amp;#39;);
					loading.value = false;
			 })
			
		}
	}).catch((err) =&amp;gt; {
		loading.value = false;
	});
}

&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="redirectvue"&gt;redirect.vue &lt;a href="#redirectvue" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5245c11" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div &amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import { useRoute, useRouter } from &amp;#39;vue-router&amp;#39;;

const route = useRoute();
const router = useRouter();

const { params, query } = route;
const { path } = params;

router.replace({ path: &amp;#39;/&amp;#39; &amp;#43; path, query });
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="routerjs"&gt;router.js定义路由 &lt;a href="#routerjs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="504f496" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;{
 path: &amp;#39;/login&amp;#39;,
 name: &amp;#39;Login&amp;#39;,
 component: () =&amp;gt; import(&amp;#39;@/views/gen/login/index.vue&amp;#39;)
 },
 {
 path: &amp;#34;/redirect/:path(.*)&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/gen/redirect/index.vue&amp;#34;),
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;路由守卫使用 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="fb16500" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import router from &amp;#34;@/router&amp;#34;;

// 白名单路由
const whiteList = [&amp;#34;/login&amp;#34;];

router.beforeEach(async (to, from, next) =&amp;gt; {
 const hasToken = localStorage.getItem(&amp;#34;token&amp;#34;);
 if (hasToken) {
 if (to.path === &amp;#34;/login&amp;#34;) {
 next({ path: &amp;#34;/&amp;#34; });
 } else {
 // 未匹配到任何路由，跳转404
 if (to.matched.length === 0) {
 from.name ? next({ name: from.name }) : next(&amp;#34;/404&amp;#34;);
 } else {
 next();
 }
 }
 
 } else {
 // 未登录可以访问白名单页面
 if (whiteList.indexOf(to.path) !== -1) {
 next();
 } else {
 next(`/login?redirect=${to.path}`);
 
 }
 }
});&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>Javadoc自动填充maven插件</title><link>https://xiaoying.org.cn/pages/6ae52b/</link><pubDate>Sat, 26 Apr 2025 12:43:13 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6ae52b/</guid><description>&lt;h2 id="heading"&gt;背景 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;发布到中央仓库时需要javadoc注释，所以写了这个maven插件用于在构建阶段自动生成注释。该插件同时支持Java 8和Java 17版本。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;特性 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;同时支持Java 8和Java 17及以上&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模块化设计&lt;/strong&gt;：将代码按职责拆分为多个类，提高代码的可维护性和可扩展性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置灵活性&lt;/strong&gt;：增加了多个配置选项，允许用户自定义Javadoc生成行为&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;：改进了异常处理机制，提高代码的健壮性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码复用&lt;/strong&gt;：提取重复代码为通用方法，减少代码冗余&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="heading-2"&gt;使用方法 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="alert alert-info" role="alert" style="padding:0.5rem 1rem;"&gt;

 
 &lt;div class="d-flex align-items-start mb-1"&gt;
 
 &lt;span
 class="material-icons d-flex align-items-center justify-content-center rounded-circle text-primary"
 style="width:2rem; height:2rem; font-size:1.25rem; flex-shrink:0; background-color: var(--bgcolor );"&gt;
 lightbulb
 &lt;/span&gt;

 &lt;span class="alert-title fw-semibold fs-5 mt-0"&gt;info&lt;/span&gt;
 &lt;/div&gt;

 
 
 &lt;div&gt;依赖可能非最新版本，请前往&lt;a href="https://central.sonatype.com/artifact/io.github.liyao52033/autofill-javadoc-maven-plugin" rel="external" target="_blank"&gt;maven&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;获取最新版本&lt;/div&gt;
 

&lt;/div&gt;

&lt;h3 id="heading-3"&gt;单独使用 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="26d2d45" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;build&amp;gt;
 &amp;lt;plugins&amp;gt;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;io.github.liyao52033&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;autofill-javadoc-maven-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
 &amp;lt;executions&amp;gt;
 &amp;lt;execution&amp;gt;
 &amp;lt;goals&amp;gt;
 &amp;lt;goal&amp;gt;autofill&amp;lt;/goal&amp;gt;
 &amp;lt;/goals&amp;gt;
 &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt; 
 &amp;lt;/execution&amp;gt;
 &amp;lt;/executions&amp;gt;
 &amp;lt;configuration&amp;gt;
 &amp;lt;sourceDir&amp;gt;src/main/java&amp;lt;/sourceDir&amp;gt; &amp;lt;!-- 指定源代码目录 --&amp;gt;
 &amp;lt;addClassJavadoc&amp;gt;true&amp;lt;/addClassJavadoc&amp;gt; &amp;lt;!-- 是否添加类注释 --&amp;gt;
 &amp;lt;addMethodJavadoc&amp;gt;true&amp;lt;/addMethodJavadoc&amp;gt; &amp;lt;!-- 是否添加方法注释 --&amp;gt;
 &amp;lt;addParamJavadoc&amp;gt;true&amp;lt;/addParamJavadoc&amp;gt; &amp;lt;!-- 是否添加参数注释 --&amp;gt;
 &amp;lt;addReturnJavadoc&amp;gt;true&amp;lt;/addReturnJavadoc&amp;gt; &amp;lt;!-- 是否添加返回值注释 --&amp;gt;
 &amp;lt;addThrowsJavadoc&amp;gt;true&amp;lt;/addThrowsJavadoc&amp;gt; &amp;lt;!-- 是否添加异常注释 --&amp;gt;
 &amp;lt;!-- 高级配置选项 --&amp;gt;
 &amp;lt;excludePatterns&amp;gt;
 &amp;lt;excludePattern&amp;gt;.*\/generated\/.*&amp;lt;/excludePattern&amp;gt; &amp;lt;!-- 排除生成的代码 --&amp;gt;
 &amp;lt;excludePattern&amp;gt;.*Test\.java&amp;lt;/excludePattern&amp;gt; &amp;lt;!-- 排除测试文件 --&amp;gt;
 &amp;lt;/excludePatterns&amp;gt;
 &amp;lt;includePrivateMethods&amp;gt;false&amp;lt;/includePrivateMethods&amp;gt; &amp;lt;!-- 是否包含私有方法 --&amp;gt;
 &amp;lt;/configuration&amp;gt;
 &amp;lt;/plugin&amp;gt;
 &amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="maven-javadoc-plugin"&gt;与maven-javadoc-plugin集成发布到中央仓库 &lt;a href="#maven-javadoc-plugin" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="349a18f" class="language-xml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;build&amp;gt;
 &amp;lt;plugins&amp;gt;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;org.sonatype.central&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;central-publishing-maven-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;0.5.0&amp;lt;/version&amp;gt;
 &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;
 &amp;lt;configuration&amp;gt;
 &amp;lt;publishingServerId&amp;gt;xxx&amp;lt;/publishingServerId&amp;gt;
 &amp;lt;checksums&amp;gt;required&amp;lt;/checksums&amp;gt;
 &amp;lt;deploymentName&amp;gt;xxx&amp;lt;/deploymentName&amp;gt;
 &amp;lt;/configuration&amp;gt;
 &amp;lt;/plugin&amp;gt;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;maven-source-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.2.1&amp;lt;/version&amp;gt;
 &amp;lt;executions&amp;gt;
 &amp;lt;execution&amp;gt;
 &amp;lt;id&amp;gt;attach-sources&amp;lt;/id&amp;gt;
 &amp;lt;phase&amp;gt;verify&amp;lt;/phase&amp;gt;
 &amp;lt;goals&amp;gt;
 &amp;lt;goal&amp;gt;jar-no-fork&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;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;io.github.liyao52033&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;autofill-javadoc-maven-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;
 &amp;lt;executions&amp;gt;
 &amp;lt;execution&amp;gt;
 &amp;lt;goals&amp;gt;
 &amp;lt;goal&amp;gt;autofill&amp;lt;/goal&amp;gt;
 &amp;lt;/goals&amp;gt;
 &amp;lt;phase&amp;gt;generate-sources&amp;lt;/phase&amp;gt; &amp;lt;!-- 确保在javadoc之前运行 --&amp;gt;
 &amp;lt;/execution&amp;gt;
 &amp;lt;/executions&amp;gt;
 &amp;lt;configuration&amp;gt;
 &amp;lt;sourceDir&amp;gt;src/main/java&amp;lt;/sourceDir&amp;gt; &amp;lt;!-- 指定源代码目录 --&amp;gt;
 &amp;lt;/configuration&amp;gt;
 &amp;lt;/plugin&amp;gt;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;maven-javadoc-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.5.0&amp;lt;/version&amp;gt;
 &amp;lt;configuration&amp;gt;
 &amp;lt;encoding&amp;gt;UTF-8&amp;lt;/encoding&amp;gt;
 &amp;lt;charset&amp;gt;UTF-8&amp;lt;/charset&amp;gt;
 &amp;lt;docencoding&amp;gt;UTF-8&amp;lt;/docencoding&amp;gt;
 &amp;lt;/configuration&amp;gt;
 &amp;lt;executions&amp;gt;
 &amp;lt;execution&amp;gt;
 &amp;lt;id&amp;gt;attach-javadocs&amp;lt;/id&amp;gt;
 &amp;lt;goals&amp;gt;
 &amp;lt;goal&amp;gt;jar&amp;lt;/goal&amp;gt;
 &amp;lt;/goals&amp;gt;
 &amp;lt;phase&amp;gt;verify&amp;lt;/phase&amp;gt; &amp;lt;!-- Javadoc 生成在 verify 阶段运行 --&amp;gt;
 &amp;lt;/execution&amp;gt;
 &amp;lt;/executions&amp;gt;
 &amp;lt;/plugin&amp;gt;
 &amp;lt;plugin&amp;gt;
 &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;maven-gpg-plugin&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;3.2.7&amp;lt;/version&amp;gt;
 &amp;lt;executions&amp;gt;
 &amp;lt;execution&amp;gt;
 &amp;lt;id&amp;gt;sign-artifacts&amp;lt;/id&amp;gt;
 &amp;lt;phase&amp;gt;verify&amp;lt;/phase&amp;gt;
 &amp;lt;goals&amp;gt;
 &amp;lt;goal&amp;gt;sign&amp;lt;/goal&amp;gt;
 &amp;lt;/goals&amp;gt;
 &amp;lt;/execution&amp;gt;
 &amp;lt;/executions&amp;gt;
 &amp;lt;configuration&amp;gt;
 &amp;lt;gpgArguments&amp;gt;
 &amp;lt;arg&amp;gt;--pinentry-mode&amp;lt;/arg&amp;gt;
 &amp;lt;arg&amp;gt;loopback&amp;lt;/arg&amp;gt;
 &amp;lt;/gpgArguments&amp;gt;
 &amp;lt;/configuration&amp;gt;
 &amp;lt;/plugin&amp;gt;
 &amp;lt;/plugins&amp;gt;
&amp;lt;/build&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;项目结构 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;项目结构如下：&lt;/p&gt;</description></item><item><title>ECharts</title><link>https://xiaoying.org.cn/pages/b25bff/</link><pubDate>Fri, 04 Apr 2025 02:55:11 +0000</pubDate><guid>https://xiaoying.org.cn/pages/b25bff/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;ECharts封装，不需要再单独引入Echarts，只需给定配置即可，使用请参考&lt;a href="https://echarts.apache.org/handbook/zh/how-to/chart-types/bar/basic-bar" rel="external" target="_blank"&gt;官方文档&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="heading-1"&gt;基本配置项 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="tooltip"&gt;tooltip &lt;a href="#tooltip" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;配置提示框组件，显示提示信息。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0bdf7ed" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;tooltip: {
 trigger: &amp;#39;item&amp;#39;, // 数据项图形触发
 formatter: &amp;#39;{a} &amp;lt;br/&amp;gt;{b}: {c} ({d}%)&amp;#39; // 格式化显示内容
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="legend"&gt;legend &lt;a href="#legend" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;配置图例组件，展示系列名称，提供点击筛选的功能。&lt;/p&gt;</description></item><item><title>Docker使用</title><link>https://xiaoying.org.cn/pages/2cb347/</link><pubDate>Fri, 15 Sep 2023 17:48:16 +0000</pubDate><guid>https://xiaoying.org.cn/pages/2cb347/</guid><description>&lt;h2 id="docker"&gt;docker概述 &lt;a href="#docker" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading"&gt;基本介绍 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Docker 是一个开源的应用容器引擎，基于 Go 语言 并遵从 Apache2.0 协议开源。&lt;/p&gt;
&lt;p&gt;Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。&lt;/p&gt;
&lt;p&gt;容器是完全使用沙箱机制，相互之间不会有任何接口,更重要的是容器性能开销极低。&lt;/p&gt;
&lt;p&gt;Docker 从 17.03 版本之后分为 CE（Community Edition: 社区版） 和 EE（Enterprise Edition: 企业版），我们用社区版就可以了。&lt;a href="https://docs.docker.com/" rel="external" target="_blank"&gt;官网&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>patch-package使用</title><link>https://xiaoying.org.cn/pages/6f649a/</link><pubDate>Thu, 31 Aug 2023 11:30:19 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6f649a/</guid><description>&lt;p&gt;::: info&lt;/p&gt;
&lt;p&gt;使用 &lt;code&gt;patch-package&lt;/code&gt; 修改第三方模块，及时解决第三方依赖包的 bug&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;:::: el-tabs&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=yarn&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4746476" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add --dev patch-package postinstall-postinstall&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::: el-tab-pane label=npm&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cf00f77" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm install patch-package --save-dev&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::::&lt;/p&gt;
&lt;h2 id="heading-1"&gt;创建补丁 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;直接在项目根目录下的 &lt;code&gt;node_modules&lt;/code&gt; 文件夹中找到要修改依赖包的相关文件，然后回到根目录执行&lt;/p&gt;
&lt;p&gt;:::: el-tabs&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=yarn&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="84e784d" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn patch-package package-name&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::: el-tab-pane label=npm&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="eaee6ed" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npx patch-package package-name&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::::&lt;/p&gt;</description></item><item><title>TortosseGit的ssh配置</title><link>https://xiaoying.org.cn/pages/76b509/</link><pubDate>Thu, 31 Aug 2023 11:39:21 +0000</pubDate><guid>https://xiaoying.org.cn/pages/76b509/</guid><description>&lt;h2 id="gitssh"&gt;&lt;strong&gt;GIT的ssh配置&lt;/strong&gt; &lt;a href="#gitssh" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;git生成密钥最好通过ssh-gen命令直接生成，因为会自动保存到 home/.ssh目录下。而且是openssh格式。
使用命令&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5659495" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;ssh-keygen -t rsa -C ‘example@qq.com’&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;一路回车，将id_rsa.pub拷贝到github或其他服务器，就可以使用ssh登陆了。&lt;/p&gt;
&lt;h2 id="tortoisegit-ssh"&gt;TortoiseGit 设置ssh方式 &lt;a href="#tortoisegit-ssh" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;TortoiseGit使用扩展名为ppk的密钥，而不是ssh-keygen生成的rsa密钥。&lt;/p&gt;
&lt;p&gt;也就是说使用 ssh-keygen -t rsa -C &amp;ldquo;&lt;a href="mailto:576953565@qq.com" rel="external" target="_blank"&gt;576953565@qq.com&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&amp;quot;产生的密钥，TortoiseGit中不能用。&lt;/p&gt;</description></item><item><title>TextScroll</title><link>https://xiaoying.org.cn/pages/41500d/</link><pubDate>Fri, 04 Apr 2025 01:38:17 +0000</pubDate><guid>https://xiaoying.org.cn/pages/41500d/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;文本滚动公告&lt;/p&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4b1e27f" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;app-container&amp;#34;&amp;gt;
 &amp;lt;!-- 基础用法 --&amp;gt;
 &amp;lt;TextScroll text=&amp;#34;这是一条基础的滚动公告，默认向左滚动。&amp;#34; typewriter /&amp;gt;

 &amp;lt;!-- 使用不同的类型 --&amp;gt;
 &amp;lt;TextScroll type=&amp;#34;success&amp;#34; text=&amp;#34;这是一条成功类型的滚动公告&amp;#34; typewriter /&amp;gt;

 &amp;lt;TextScroll type=&amp;#34;warning&amp;#34; text=&amp;#34;这是一条警告类型的滚动公告&amp;#34; /&amp;gt;

 &amp;lt;TextScroll type=&amp;#34;danger&amp;#34; text=&amp;#34;这是一条危险类型的滚动公告&amp;#34; /&amp;gt;

 &amp;lt;TextScroll type=&amp;#34;info&amp;#34; text=&amp;#34;这是一条信息类型的滚动公告&amp;#34; /&amp;gt;

 &amp;lt;!-- 自定义速度和方向 --&amp;gt;
 &amp;lt;TextScroll text=&amp;#34;这是一条速度较慢、向右滚动的公告&amp;#34; :speed=&amp;#34;30&amp;#34; direction=&amp;#34;right&amp;#34; showClose /&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import { TextScroll } from &amp;#34;liyao-vue-common&amp;#34;;
&amp;lt;/script&amp;gt;

&amp;lt;style lang=&amp;#34;scss&amp;#34; scoped&amp;gt;
.app-container {
 :deep(.text-scroll-container) {
 margin-bottom: 20px;
 }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>nginx常用配置</title><link>https://xiaoying.org.cn/pages/3a2ef9/</link><pubDate>Fri, 01 Sep 2023 09:58:20 +0000</pubDate><guid>https://xiaoying.org.cn/pages/3a2ef9/</guid><description>&lt;h2 id="https"&gt;配置HTTPS &lt;a href="#https" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3cc53b3" class="language-nginx wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;server {
 listen 443 ssl;
 server_name xiaoying.org.cn;
 root /usr/local/dist; #前端打包文件位置

 #域名证书文件名称
 ssl_certificate /etc/nginx/xiaoying.org.cn_bundle.crt;
 #域名证书私钥文件名称
 ssl_certificate_key /etc/nginx/xiaoying.org.cn.key;
 
 #请按照以下协议配置
 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; 
 #请按照以下套件配置，配置加密套件，写法遵循 openssl 标准。
 ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; 
 ssl_prefer_server_ciphers on;
 ssl_session_cache shared:SSL:1m;
 ssl_session_timeout 10m;

 location ^~ /api/ { #后端接口前缀
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_pass http://127.0.0.1:8080; #后端接口地址
 }

 include /etc/nginx/default.d/*.conf;

 error_page 404 /404.html;
 location = /40x.html {
 }

 error_page 500 502 503 504 /50x.html;
 location = /50x.html {
 }
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="gzip"&gt;开启gzip压缩静态文件 &lt;a href="#gzip" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-gzip-"&gt;配置 GZip 压缩 &lt;a href="#-gzip-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;gzip 可以在 http, server, location 中和配置，这里配置到 http 下是全局配置，&lt;/p&gt;</description></item><item><title>Docker部署前后端分离项目</title><link>https://xiaoying.org.cn/pages/ab9341/</link><pubDate>Sat, 16 Sep 2023 11:06:57 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ab9341/</guid><description>&lt;h2 id="heading"&gt;服务器要求 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;下面的建议不包含minio的内存占用，如需使用minio，请另外考虑&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;核心数和内存大小有两种方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2核4G（使用ES搜索策略）&lt;/li&gt;
&lt;li&gt;2核2G（使用MySQL搜素策略）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;带宽大小有两种方案：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用oss对带宽没有要求（本人亲测：1M带宽+oss 访问速度很快）&lt;/li&gt;
&lt;li&gt;使用minio需要大一点的带宽（小带宽也可以，但需要使用cdn加速）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="docker"&gt;docker的安装 &lt;a href="#docker" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;以下命令基于CentOS环境。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载工具&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6f511f2" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yum install -y yum-utils&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;设置镜像的仓库&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="69c64ec" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yum-config-manager \
 --add-repo \
 https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #配置阿里云的镜像&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更新yum软件包索引&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9fbf08b" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yum makecache fast&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装docker相关配置&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8302ac1" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yum install -y docker-ce docker-ce-cli containerd.io&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启动docker&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5892fc1" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;systemctl start docker
# 查看当前版本号，是否启动成功
docker version
# 设置开机自启动
systemctl enable docker&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id="mysql"&gt;安装mysql &lt;a href="#mysql" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="1-"&gt;方式1: 无挂载模式 &lt;a href="#1-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;

 &lt;blockquote&gt;
 &lt;p&gt;这种方式直接运行mysql之后，所有关于mysql的内容都在容器中，后续如果需要修改mysql的内容，需要手动进入容器内进行操作。且在宿主机上无备份，一旦容器被删除，数据也会被删除。&lt;/p&gt;</description></item><item><title>node后端部署</title><link>https://xiaoying.org.cn/pages/ea2a03/</link><pubDate>Thu, 10 Apr 2025 16:06:22 +0000</pubDate><guid>https://xiaoying.org.cn/pages/ea2a03/</guid><description>&lt;h2 id="heading"&gt;目录结构 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;需要上传到服务器的文件如下&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="1fbc2b5" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;├── backend
│ └── server.js //node后端
├── deploy.sh
├── dist //打包产物
│ ├── assets
│ ├── favicon.ico
├── Dockerfile
├── nginx
│ └── default.conf
├── package.json&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="dockerfile"&gt;Dockerfile &lt;a href="#dockerfile" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="41cb7bc" class="language-dockerfile wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;# 使用 Node 官方镜像
FROM node:18-alpine

# 设置工作目录
WORKDIR /app

# 拷贝后端文件（假设 server.js 和 package.json 都在当前目录）
COPY backend/server.js package.json ./

# 安装依赖和 pm2
RUN npm config set registry https://registry.npmmirror.com &amp;amp;&amp;amp; \
 npm install --no-audit --no-fund &amp;amp;&amp;amp; \
 npm install -g pm2 --no-audit --no-fund


# 开放端口（如果后端监听 3600）
EXPOSE 3600

# 使用 pm2 启动
CMD [&amp;#34;pm2-runtime&amp;#34;, &amp;#34;server.js&amp;#34;]&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="deploysh"&gt;deploy.sh &lt;a href="#deploysh" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7742508" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;#!/bin/bash
set -e

PROJECT_NAME=sha1-checker

echo &amp;#34;🔄 停止并删除旧容器...&amp;#34;
sudo docker stop $PROJECT_NAME || true
sudo docker rm $PROJECT_NAME || true

echo &amp;#34;🔧 构建镜像...&amp;#34;
sudo docker build -t $PROJECT_NAME .

echo &amp;#34;🚀 启动容器...&amp;#34;
sudo docker run -d \
 --name $PROJECT_NAME \
 -p 3600:3600 \
 $PROJECT_NAME

echo &amp;#34;✅ 部署完成！访问: https://maven.xiaoying.org.cn/&amp;#34;

# echo &amp;#34;📄 后端日志输出：&amp;#34;
docker logs -f $PROJECT_NAME&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="nginxconf"&gt;nginx.conf &lt;a href="#nginxconf" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4a5abdd" class="language-ng wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;server {
 listen 443 ssl;
 server_name maven.xiaoying.org.cn;

 ssl_certificate /etc/nginx/fullchain.cer;
 ssl_certificate_key /etc/nginx/xiaoying.org.cn.key;
 ssl_session_cache shared:SSL:1m;
 ssl_session_timeout 10m;
 ssl_ciphers HIGH:!aNULL:!MD5;
 ssl_prefer_server_ciphers on;

 client_max_body_size 50m;

 location / {
 root /usr/local/maven/dist;
 index index.html;
 try_files $uri $uri/ /index.html;
 }

 location /api/ {
 proxy_set_header Host $host;
 proxy_set_header X-Forwarded-Proto $scheme;
 proxy_set_header X-Real-IP $remote_addr;
 proxy_pass http://127.0.0.1:3600;
 }
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="publishsh"&gt;publish.sh &lt;a href="#publishsh" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ccca06a" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;#!/bin/bash

set -e
set -x

# 远程服务器信息
REMOTE_USER=&amp;#34;root&amp;#34;
REMOTE_SERVER=&amp;#34;服务器IP&amp;#34;
REMOTE_DIR=&amp;#34;/usr/local/maven&amp;#34;
NGINX_DIR=&amp;#34;/etc/nginx/conf.d&amp;#34;

FILES_TO_COPY=&amp;#34;dist backend nginx Dockerfile deploy.sh package.json&amp;#34;

# === 打包并拷贝代码 ===
echo &amp;#34;📦 打包代码...&amp;#34;

rm -f app.tar.gz
tar czf app.tar.gz $FILES_TO_COPY

echo &amp;#34;🚀 拷贝代码到服务器 $REMOTE_SERVER ...&amp;#34;
scp app.tar.gz &amp;#34;$REMOTE_USER@$REMOTE_SERVER:/tmp/app.tar.gz&amp;#34;

# 上传到服务器后删除本地的包
rm -f app.tar.gz

# 远程登录并执行部署
ssh $REMOTE_USER@$REMOTE_SERVER &amp;lt;&amp;lt; EOF

set -e

echo &amp;#34;🧹 清理旧文件...&amp;#34;
rm -rf &amp;#34;$REMOTE_DIR&amp;#34;
mkdir -p &amp;#34;$REMOTE_DIR&amp;#34;
tar xzf /tmp/app.tar.gz -C &amp;#34;$REMOTE_DIR&amp;#34;
rm /tmp/app.tar.gz

# 删除旧的nginx配置
cd $NGINX_DIR
rm -rf sha1Checker.conf

echo &amp;#34;拷贝 nginx 配置...&amp;#34;
cp $REMOTE_DIR/nginx/default.conf $NGINX_DIR/sha1Checker.conf

#重启nginx
systemctl restart nginx

echo &amp;#34;🎉 前端部署完成，开始部署后端！&amp;#34;

echo &amp;#34;Checking for deploy.sh...&amp;#34;
if [ -f &amp;#34;$REMOTE_DIR/deploy.sh&amp;#34; ]; then
 echo &amp;#34;deploy.sh found.&amp;#34;
 cd $REMOTE_DIR
 chmod &amp;#43;x deploy.sh
 ./deploy.sh
else
 echo &amp;#34;deploy.sh not found.&amp;#34;
fi
EOF&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;部署 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;打开Git Bash ，在项目根目录下执行&lt;/p&gt;</description></item><item><title>docker-compose使用</title><link>https://xiaoying.org.cn/pages/3aabf1/</link><pubDate>Sat, 30 Sep 2023 12:56:14 +0000</pubDate><guid>https://xiaoying.org.cn/pages/3aabf1/</guid><description>&lt;h2 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;需提前安装 Docker Engine 和 Docker CLI，参考&lt;a href="https://xiaoying.org.cn/pages/74f6d1/#_2-docker%E7%9A%84%E5%AE%89%E8%A3%85" rel="external" target="_blank"&gt;docker安装&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ae7f98c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yum install docker-compose&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;通过检查版本来验证 Docker Compose 是否正确安装&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d14b144" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;docker-compose -version&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;使用 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;::: info 提示&lt;/p&gt;</description></item><item><title>常用hooks</title><link>https://xiaoying.org.cn/pages/fad018/</link><pubDate>Wed, 26 Mar 2025 03:05:58 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fad018/</guid><description>&lt;h2 id="usebusuanzi"&gt;useBusuanzi &lt;a href="#usebusuanzi" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;给网站、博客文章添加阅读次数统计&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c31e7f8" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import { useBusuanzi } from &amp;#34;liyao-vue-common&amp;#34;;
const { site_pv, site_uv, page_pv, page_uv } = useBusuanzi();
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;p&amp;gt;站点访问量: {{ site_pv }}&amp;lt;/p&amp;gt;
 &amp;lt;p&amp;gt;站点访客数: {{ site_uv }}&amp;lt;/p&amp;gt;
 &amp;lt;p&amp;gt;当前页面访问量: {{ page_pv }}&amp;lt;/p&amp;gt;
 &amp;lt;p&amp;gt;当前页面访客数: {{ page_uv }}&amp;lt;/p&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="usedaydiff"&gt;useDayDiff &lt;a href="#usedaydiff" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;计算给定时间的相差天数&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="f5f659b" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { useDayDiff } from &amp;#34;liyao-vue-common&amp;#34;;
const { diffDays } = useDayDiff(&amp;#34;2024-01-01&amp;#34;);
console.log(diffDays.value); &lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="usetimediff"&gt;useTimeDiff &lt;a href="#usetimediff" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;计算给定时间的相差时间(年/月/日/时/分)&lt;/p&gt;</description></item><item><title>mounted阶段获取不到dom的原因及解决方法</title><link>https://xiaoying.org.cn/pages/cf6790/</link><pubDate>Thu, 11 Jan 2024 22:39:33 +0000</pubDate><guid>https://xiaoying.org.cn/pages/cf6790/</guid><description>&lt;h2 id="heading"&gt;问题描述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;需要在dom渲染后，获取dom来进行页面自动滚动到需要的位置。
在mounted阶段用document.querySelector()以及this.$refs获取元素均获取不到。用两种方式获取元素，打印出来的结果都是undefined。
有解答说用this.nextTick(function(){…})，试了一下结果还是undefined&lt;/p&gt;
&lt;h2 id="heading-1"&gt;分析原因 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;1、Vue 推荐使用 template 来创建 HTML。但是模板毕竟是模板，不是真实的dom节点。vue会先利用对象中的render 函数**，**生成虚拟节点并挂载，挂载的真实DOM是进行异步渲染的，并且在修改完状态后也是异步的方式进行渲染。代码中将document.querySelector操作定义为同步任务，此时事件队列应该是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同步队列：获取dom元素，&lt;/li&gt;
&lt;li&gt;异步队列：从虚拟节点转真实节点并进行渲染&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据先同步后异步的执行流程，是获取不到dom元素的；&lt;/p&gt;
&lt;p&gt;2、在mounted阶段，若需要获取的元素或组件有v-if，v-for属性。v-if的初始化结果为false。v-for&lt;a href="https://so.csdn.net/so/search?q=遍历&amp;spm=1001.2101.3001.7020" rel="external" target="_blank"&gt;遍历&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;的数组初始化阶段无值。（即mounted阶段后，根据获得的后台数据来动态操作dom）这两种情况都会导致mounted阶段获取元素的语句获取不到dom。&lt;/p&gt;
&lt;h2 id="heading-2"&gt;解决方法 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;1、把获取元素的语句放在异步获取到数据，赋值给data中的key之后进行。同时需要给获取元素的语句加上setTimeout。因为setTimeout是宏任务，会在vue的render函数执行之后再执行。&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0b9b3af" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; mounted() {
 setTimeout(() =&amp;gt; {
 if (this.$route.path !== &amp;#34;/&amp;#34;) {
 let rightbar = document.querySelector(&amp;#34;.right-menu-wrapper&amp;#34;);
 let arrow = document.querySelector(&amp;#34;.page-nav-centre-next&amp;#34;);

 if (rightbar) {
 arrow.style.right = &amp;#34;16rem&amp;#34;;
 } else {
 arrow.style.right = &amp;#34;2rem&amp;#34;; 
 }
 }
 }, 200);
 
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;2、把获取元素的语句放到updated周期中执行。这种情况下每次视图更新之后都会执行一次获取元素的语句，如果不需要每次视图更新之后都执行，可以在mounted周期中，使用可以在mounted周期中，使用this.$once让获取元素的语句只在updated阶段执行一次。&lt;/p&gt;</description></item><item><title>代码上线事故原因</title><link>https://xiaoying.org.cn/pages/fa3d0b/</link><pubDate>Wed, 10 Jan 2024 09:24:03 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fa3d0b/</guid><description>&lt;h3 id="heading"&gt;本地代码误发线上 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这个问题本质上是由于粗心导致的，很多同学为了自己本地开发方便，可能写了一些模拟数据、特殊逻辑（比如不判断用户权限），但是最后上线前不检查，就直接把特殊逻辑发到线上了，导致各种各样 “哭笑不得” 的问题。&lt;/p&gt;
&lt;p&gt;这里有 2 种预防方式：&lt;/p&gt;
&lt;p&gt;1）使用 CR（Code Review）机制，在自己的代码发布前，由同事或上级来检查代码，从而提前发现一些问题。&lt;/p&gt;
&lt;p&gt;2）不要写仅本地可用的代码、尽量不写和环境有关的特殊逻辑，保证自己写的每行代码都是可发布上线的&lt;/p&gt;
&lt;p&gt;虽然这个问题可以预防，但是无法根治，因为人本身就是最大的 Bug，一个再牛的人也可能会犯一些小错误。&lt;/p&gt;
&lt;h3 id="heading-1"&gt;环境差异 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;很多时候，同一套代码换一个环境可能就跑不通了。比如操作系统、网络连通、依赖服务、依赖版本、防火墙安全设置等等的差异。&lt;/p&gt;
&lt;p&gt;举个典型的例子，本地的数据库新增了字段，测试通过了；结果上线前忘了在线上数据库同步新增字段，就导致数据库相关功能崩掉。&lt;/p&gt;
&lt;p&gt;要解决这个问题，最好的办法就是尽量保证本地环境和线上环境一致，比如使用 Docker 容器等虚拟化技术来模拟线上环境运行。或者在正式上线前，通过测试环境、预发布环境来测试部署，降低环境差异的风险。&lt;/p&gt;
&lt;p&gt;此外还有个建议，对于核心项目，团队内最好能整理出一个规范的部署文档、明确定义项目运行的环境，保证团队成员都能提前知晓这些信息并正确配置环境。&lt;/p&gt;
&lt;h3 id="heading-2"&gt;配置差异 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;由于本地和线上的环境可能存在差异，我们适用于本地的项目配置文件不一定适用于线上。&lt;/p&gt;
&lt;p&gt;比如 Java 项目的 application.yml 文件，一般会定义项目启动的端口、依赖的数据库服务配置、cookie 配置等。如果在配置文件中指定项目在 8080 端口启动，你自己的电脑上运行可能没问题，但为啥发到线上就运行不起来或无法访问呢？&lt;/p&gt;
&lt;p&gt;大概率是因为线上服务器的 8080 端口已经被其他人占用了；或者没有给该端口开启防火墙，导致无法访问。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，通常我们会分别为本地和线上指定不同的配置，比如区分 &lt;code&gt;application-dev.yml&lt;/code&gt; 、&lt;code&gt;application-prod.yml&lt;/code&gt; 等，不同的环境加载不同的配置文件。&lt;/p&gt;
&lt;p&gt;还可以使用一些可视化的配置管理工具（比如 Apollo、Nacos），让管理员统一在工具上发布不同环境的配置，并通过工具校验配置并记录变更，减少人工导致的配置差错。&lt;/p&gt;
&lt;h3 id="heading-3"&gt;资源路径差异 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;如果你的项目中引用了本地文件（比如 C 盘的 xxx.txt），那么上线后大概率会报错。因为线上的服务器并没有该路径、或者在该路径下没有文件。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，建议大家尽量使用相对路径去加载资源；或者使用集中的分布式文件系统、对象存储服务等，给每个资源一个统一确定的标识（比如网址），保证各机器上都能用相同的路径找到该资源。&lt;/p&gt;
&lt;h3 id="api-"&gt;API 接口差异 &lt;a href="#api-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这个问题更多地是出现在前端。一般情况下，前端本地调试时请求的是后端的开发服务，而上线后请求的是线上服务。不仅请求的路径不同的，还可能出现跨域问题，导致接口请求失败、无法登录等问题。&lt;/p&gt;
&lt;p&gt;所以尽量保证开发和线上接口的路径规范一致，对于跨域问题可以使用 Nginx 网关的反向代理功能统一解决。&lt;/p&gt;
&lt;p&gt;另外，在企业开发中，一般开发环境和线上环境的网络是隔离的。如果你的代码依赖一些第三方接口，一定要注意接口的网络连通性、接口的性能差异等问题，提前做好相关的测试。不要等到上线后才发现，我 c，接口怎么调不通啊？！&lt;/p&gt;
&lt;p&gt;还有一种情况，在使用有回调功能的第三方服务（比如公众号开发）时经常会出现，那就是忘记了修改第三方服务的回调地址。而且这种错误不好排查，因为你能请求通别人的服务，只不过别人的服务通知不到你罢了。所以要格外留意这种情况。&lt;/p&gt;
&lt;h3 id="heading-4"&gt;用量差异 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这是所有上线出 Bug 的情况中，我个人认为最高级的了，而且很难绝对避免。&lt;/p&gt;</description></item><item><title>Invoker Commands API 说明文档</title><link>https://xiaoying.org.cn/pages/628f0d/</link><pubDate>Tue, 03 Mar 2026 20:14:24 +0000</pubDate><guid>https://xiaoying.org.cn/pages/628f0d/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;HTML Invoker Commands API 是 Web 平台上一个新兴的声明式 API，通过 HTML 本身就能控制 UI 交互元素（如弹出框、对话框等），减少对手写 JavaScript 的依赖，从而改善页面首屏加载体验。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="heading"&gt;背景与目标 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;过去常见的交互模式，比如点击按钮弹出一个对话框、显示/隐藏弹出菜单等，需要开发者编写大量事件监听器和逻辑代码。在资源受限或初始加载场景下，这会导致延迟和性能问题。Invoker Commands API 的目标是用原生、声明式的方式，通过 HTML 直接表达这些行为，减少开发和运行时对 JavaScript 的依赖，从而提高交互的即时性和可访问性。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;核心概念 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;声明式控制按钮 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Invoker Commands API 为 &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; 元素增加了两个核心属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;commandfor&lt;/code&gt;：指定该按钮控制的目标元素 ID&lt;/li&gt;
&lt;li&gt;&lt;code&gt;command&lt;/code&gt;：定义要执行的操作名称&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两者联合起来，使按键行为可以由浏览器原生执行，不再需要手写监听器。&lt;/p&gt;
&lt;h2 id="html-"&gt;HTML 属性详解 &lt;a href="#html-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;属性&lt;/th&gt;
 &lt;th&gt;类型&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;commandfor&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;目标元素的 id，用于指定被控制元素&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;command&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;string&lt;/td&gt;
 &lt;td&gt;执行的命令标识（如内置命令或自定义命令）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-3"&gt;内置命令 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;当前 API 内置了一些常用命令，用于控制 UI 组件：&lt;/p&gt;
&lt;h3 id="popover"&gt;弹出框（Popover） &lt;a href="#popover" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;toggle-popover&lt;/code&gt;：切换显示 / 隐藏状态&lt;/li&gt;
&lt;li&gt;&lt;code&gt;show-popover&lt;/code&gt;：显示弹出框&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hide-popover&lt;/code&gt;：隐藏弹出框&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="dialog"&gt;对话框（Dialog） &lt;a href="#dialog" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;show-modal&lt;/code&gt;：以模态方式展示对话框&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close&lt;/code&gt;：关闭对话框&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些命令可以让按钮直接控制对应的组件行为，而不必绑定事件处理器。&lt;/p&gt;</description></item><item><title>useScript</title><link>https://xiaoying.org.cn/pages/9bdc8b/</link><pubDate>Fri, 04 Apr 2025 07:53:35 +0000</pubDate><guid>https://xiaoying.org.cn/pages/9bdc8b/</guid><description>&lt;h2 id="heading"&gt;异步加载第三方脚本 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="86a1803" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;p v-if=&amp;#34;isLoading&amp;#34;&amp;gt;脚本正在加载中...&amp;lt;/p&amp;gt;
 &amp;lt;p v-if=&amp;#34;success&amp;#34;&amp;gt;脚本加载成功！&amp;lt;/p&amp;gt;
 &amp;lt;p v-if=&amp;#34;error &amp;amp;&amp;amp; isTimeout&amp;#34;&amp;gt;脚本加载超时，已重试 {{ getRetryCount() }} 次。&amp;lt;/p&amp;gt;
 &amp;lt;p v-if=&amp;#34;error &amp;amp;&amp;amp; !isTimeout&amp;#34;&amp;gt;脚本加载出错，请检查脚本链接或网络状况。&amp;lt;/p&amp;gt;
 &amp;lt;button @click=&amp;#34;runScriptDependentFunction&amp;#34; :disabled=&amp;#34;!success&amp;#34;&amp;gt;运行依赖脚本的功能&amp;lt;/button&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import { useScript } from &amp;#39;liyao-vue-common&amp;#39;;

const { isLoading, error, success, isTimeout } = useScript({
 src: &amp;#39;https://example.com/your-script.js&amp;#39;,
});

const runScriptDependentFunction = () =&amp;gt; {
 if (success.value) {
 // 调用脚本中定义的函数
 window.doSomething(); 
 }
};
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;顺序加载多个脚本 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;顺序加载指的是按顺序依次加载脚本，前一个脚本加载完成后再加载下一个脚本。可以使用 &lt;code&gt;async/await&lt;/code&gt; 或者 &lt;code&gt;Promise&lt;/code&gt; 的链式调用来实现。&lt;/p&gt;</description></item><item><title>浏览器调试</title><link>https://xiaoying.org.cn/pages/0f1523/</link><pubDate>Thu, 31 Aug 2023 11:00:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/0f1523/</guid><description>&lt;p&gt;调试网页和 Node.js 的代码，可以在代码某一行打个断点，代码执行到这里的时候就会断住，可以看它的作用域、调用栈等。&lt;/p&gt;
&lt;p&gt;但有的时候，我们并不知道应该在哪里打断点：&lt;/p&gt;
&lt;p&gt;比如代码抛了异常，你想打个断点看看异常出现的原因，但你并不知道异常在哪里发生的。&lt;/p&gt;
&lt;p&gt;比如 dom 被某个地方修改了，你想打个断点看看怎么修改的，但你并不知道是哪段代码修改了它。&lt;/p&gt;
&lt;p&gt;比如有的断点你想只在满足某个条件的时候断住，不满足条件就不需要断住。&lt;/p&gt;
&lt;p&gt;类似的情况有很多，需要断住，但是普通的断点又不大合适，这时候就需要其他的断点类型了。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;p&gt;我们分别来看一下：&lt;/p&gt;
&lt;h2 id="heading"&gt;异常断点 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;代码抛了异常，你想知道在哪抛的，这时候就可以用异常断点。&lt;/p&gt;
&lt;p&gt;比如这样一段代码：&lt;/p&gt;
&lt;p&gt;function add(a, b) { throw Error(&amp;lsquo;add&amp;rsquo;); return a + b; } console.log(add(1, 2));&lt;/p&gt;
&lt;p&gt;add 函数里抛了个异常，你想在异常处断住，这时候就可以加个异常断点：&lt;/p&gt;
&lt;p&gt;用 node 的调试来跑：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20251004140849310.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20251004140849310.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20251004140849310.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20251004140849310.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20251004140849310.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20251004140849310.png?w=2400 2400w
 " sizes="100vw" alt="" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;勾选 Uncaught Exceptions：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20251004140857948.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20251004140857948.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20251004140857948.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20251004140857948.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20251004140857948.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20251004140857948.png?w=2400 2400w
 " sizes="100vw" alt="" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;它可以在没有被处理的错误或者 Promise 的 reject 处断住。&lt;/p&gt;
&lt;p&gt;上面那个 Caught Exception 是在被 catch 处理的异常出断住。&lt;/p&gt;</description></item><item><title>useWatermark</title><link>https://xiaoying.org.cn/pages/7ad229/</link><pubDate>Fri, 04 Apr 2025 07:53:35 +0000</pubDate><guid>https://xiaoying.org.cn/pages/7ad229/</guid><description>&lt;h2 id="heading"&gt;说明 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;设置防篡改水印&lt;/p&gt;
&lt;h2 id="heading-1"&gt;参数 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="d422202" class="language-typescript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;type waterMarkOptions = {
 // 自定义水印的文字大小
 fontSize?: number;
 // 自定义水印的文字颜色
 fontColor?: string;
 // 自定义水印的文字字体
 fontFamily?: string;
 // 自定义水印的文字对齐方式
 textAlign?: CanvasTextAlign;
 // 自定义水印的文字基线
 textBaseline?: CanvasTextBaseline;
 // 自定义水印的文字倾斜角度
 rotate?: number;
};&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;使用 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;默认添加到&lt;code&gt;document.body&lt;/code&gt;，如果添加到其他元素要保证添加水印的元素（此例中为 &lt;code&gt;#app&lt;/code&gt;）的 &lt;code&gt;position&lt;/code&gt; 属性设为 &lt;code&gt;relative&lt;/code&gt; 或者 &lt;code&gt;absolute&lt;/code&gt;，这样水印才能正确定位。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可按需调整 &lt;code&gt;waterMarkOptions&lt;/code&gt; 对象里的配置选项，例如 &lt;code&gt;fontSize&lt;/code&gt;、&lt;code&gt;fontColor&lt;/code&gt;、&lt;code&gt;rotate&lt;/code&gt; 等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="1db8d1f" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div id=&amp;#34;app&amp;#34;&amp;gt;
 &amp;lt;h1&amp;gt;水印示例&amp;lt;/h1&amp;gt;
 &amp;lt;button @click=&amp;#34;addWatermark&amp;#34;&amp;gt;添加水印&amp;lt;/button&amp;gt;
 &amp;lt;button @click=&amp;#34;removeWatermark&amp;#34;&amp;gt;移除水印&amp;lt;/button&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
import { ref } from &amp;#39;vue&amp;#39;;
import { useWatermark } from &amp;#39;liyao-vue-common&amp;#39;; 

const appRef = ref&amp;lt;HTMLElement | null&amp;gt;(null);

const { setWatermark, clear } = useWatermark(appRef, {
 // waterMarkOptions...
 fontSize: 16,
 fontColor: &amp;#39;rgba(0, 0, 0, 0.2)&amp;#39;,
 rotate: 30
});

const addWatermark = () =&amp;gt; {
 setWatermark(&amp;#39;自定义水印文本&amp;#39;);
};

const removeWatermark = () =&amp;gt; {
 clear();
};
&amp;lt;/script&amp;gt;

&amp;lt;style scoped&amp;gt;
#app {
 position: relative;
 padding: 20px;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>Webpack 的 sourcemap 配置</title><link>https://xiaoying.org.cn/pages/7ac1f2/</link><pubDate>Sun, 14 Jan 2024 15:10:30 +0000</pubDate><guid>https://xiaoying.org.cn/pages/7ac1f2/</guid><description>&lt;p&gt;webpack 的 sourcemap 配置是比较麻烦的，比如这两个配置的区别：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;eval-nosources-cheap-module-source-map&lt;/li&gt;
&lt;li&gt;hidden-source-map&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;是不是分不清楚？&lt;/p&gt;
&lt;p&gt;其实它是有规律的。&lt;/p&gt;
&lt;p&gt;你把配置写错的时候，webpack 会提示你一个正则：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141510330.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141510330.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141510330.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141510330.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141510330.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141510330.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e09742f" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;这个就是配置的规律，是几种基础配置的组合。&lt;/p&gt;
&lt;p&gt;搞懂了每一种基础配置，比如 eval、nosources、cheap、module，按照规律组合起来，也就搞懂了整体的配置。&lt;/p&gt;
&lt;p&gt;那这每一种配置都是什么意思呢？&lt;/p&gt;
&lt;p&gt;我们分别来看一下。&lt;/p&gt;
&lt;h2 id="eval"&gt;eval &lt;a href="#eval" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;eval 的 api 是动态执行 JS 代码的。比如：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141513606.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141513606.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141513606.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141513606.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141513606.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141513606.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;但有个问题，eval 的代码打不了断点。&lt;/p&gt;
&lt;p&gt;怎么解决这个问题呢？&lt;/p&gt;
&lt;p&gt;浏览器支持了这样一种特性，只要在 eval 代码的最后加上 //# sourceURL=xxx，那就会以 xxx 为名字把这段代码加到 sources 里。那不就可以打断点了么？&lt;/p&gt;
&lt;p&gt;比如这样：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141510153.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141510153.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141510153.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141510153.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141510153.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141510153.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>vscode调试 Vue 项目</title><link>https://xiaoying.org.cn/pages/cabeb3/</link><pubDate>Tue, 09 Jan 2024 12:30:42 +0000</pubDate><guid>https://xiaoying.org.cn/pages/cabeb3/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;Vue 项目的创建有两种方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 @vue/cli 创建的 webpack 作为构建工具的项目&lt;/li&gt;
&lt;li&gt;用 create-vue 创建的 vite 作为构建工具的项目&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;h2 id="-vuecli--webpack-"&gt;调试 @vue/cli 创建的 webpack 项目 &lt;a href="#-vuecli--webpack-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先安装 @vue/cli：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4bd6d6e" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn global add @vue/cli&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;然后执行以下命令创建 vue 项目：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="163ba03" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;vue create vue-demo1&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401091231025.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401091231025.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401091231025.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401091231025.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401091231025.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401091231025.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;选择 vue3 的模版。&lt;/p&gt;
&lt;p&gt;安装完之后进入到 vue-demo1 目录，执行 &lt;code&gt;npm run serve&lt;/code&gt; 把开发服务跑起来。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401091231399.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401091231399.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401091231399.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401091231399.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401091231399.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401091231399.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>.VSCode Chrome Debugger配置详解</title><link>https://xiaoying.org.cn/pages/72fc14/</link><pubDate>Sun, 14 Jan 2024 14:18:30 +0000</pubDate><guid>https://xiaoying.org.cn/pages/72fc14/</guid><description>&lt;p&gt;首先，调试配置文件不用自己创建，可以直接点击 Debug 窗口的&lt;/p&gt;
&lt;p&gt;create a launch.json file&lt;/p&gt;
&lt;p&gt;快速创建：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141420794.gif?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141420794.gif?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141420794.gif?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141420794.gif?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141420794.gif?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141420794.gif?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="launchattach"&gt;launch/attach &lt;a href="#launchattach" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;创建 Chrome Debug 配置有两种方式：launch 和 attach：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141420346.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141420346.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141420346.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141420346.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141420346.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141420346.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;它们只是 request 的配置不同：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141421187.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141421187.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141421187.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141421187.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141421187.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141421187.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;我们知道，调试就是把浏览器跑起来，访问目标网页，这时候会有一个 ws 的调试服务，我们用 frontend 的 ws 客户端连接上这个 ws 服务，就可以进行调试了。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141421531.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141421531.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141421531.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141421531.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141421531.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141421531.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>VSCode Chrome Debugger 断点映射的原理</title><link>https://xiaoying.org.cn/pages/bfff94/</link><pubDate>Sun, 14 Jan 2024 16:15:33 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bfff94/</guid><description>&lt;p&gt;经常会遇到一些断点相关的问题，比如：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在文件里打的断点是灰的，一直不生效&lt;/li&gt;
&lt;li&gt;断点断在了奇怪的文件和位置&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;不知道什么原因导致的，该怎么解决。&lt;/p&gt;
&lt;p&gt;这是因为不清楚 VSCode Debugger 里打的断点是怎么在网页里生效的。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="heading"&gt;断点映射的原理 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;我们在 VSCode 里打的断点是这样的：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141615791.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141615791.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141615791.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141615791.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141615791.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141615791.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;VSCode 会记录你在哪个文件哪行打了个断点。&lt;/p&gt;
&lt;p&gt;在 breakpoints 这里可以看到：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141615875.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141615875.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141615875.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141615875.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141615875.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141615875.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;代码经过编译打包之后，可能会产生一个 bundle.js，网页里运行的是这个 js 文件：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141615766.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141615766.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141615766.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141615766.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141615766.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141615766.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;我们打的断点最终还是在代码的运行时，也就是网页里断住的，所以在 VSCode 里打的断点会被传递给浏览器，通过 CDP 调试协议。&lt;/p&gt;
&lt;p&gt;但是问题来了，我们本地打的断点是一个绝对路径，也就是包含 ${workspaceFolder} 的路径，而网页里根本没有这个路径，那怎么断住的呢？&lt;/p&gt;</description></item><item><title>调试 Vue 源码</title><link>https://xiaoying.org.cn/pages/315292/</link><pubDate>Sun, 14 Jan 2024 14:44:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/315292/</guid><description>&lt;p&gt;首先，还是通过 vue cli 创建项目（要用 5.0 以上的 cli）：&lt;/p&gt;
&lt;p&gt;安装 @vue/cli 后执行 vue create vue-demo 创建 vue 项目：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141454651.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141454651.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141454651.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141454651.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141454651.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141454651.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;选择 vue3 的模版。&lt;/p&gt;
&lt;p&gt;安装完之后进入到 vue-demo 目录，执行 npm run serve 把开发服务跑起来。&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141455802.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141455802.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141455802.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141455802.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141455802.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141455802.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;浏览器访问，会看到渲染出的页面：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141455372.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141455372.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141455372.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141455372.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141455372.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141455372.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;修改下 vue.config.js，把 devtool 改成 source-map：&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401141455045.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401141455045.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401141455045.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401141455045.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401141455045.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401141455045.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>vuepress-plugin-element-ui</title><link>https://xiaoying.org.cn/pages/60cac2/</link><pubDate>Fri, 01 Sep 2023 14:13:33 +0000</pubDate><guid>https://xiaoying.org.cn/pages/60cac2/</guid><description>&lt;h2 id="usage"&gt;usage &lt;a href="#usage" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;:::: el-tabs&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=install&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3d377f3" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add vuepress-plugin-element-ui -D
yarn add core-js@2.6.12&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=use&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="329d414" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// .vuepress/config.js
module.exports = {
 plugins: [
 &amp;#39;element-ui&amp;#39;
 ]
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=docs
&lt;a href="https://lq782655835.github.io/vuepress-plugin-element-ui/" rel="external" target="_blank"&gt;使用文档&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;
:::&lt;/p&gt;</description></item><item><title>vue-element-admin使用</title><link>https://xiaoying.org.cn/pages/9b14d2/</link><pubDate>Fri, 25 Aug 2023 11:12:39 +0000</pubDate><guid>https://xiaoying.org.cn/pages/9b14d2/</guid><description>&lt;h2 id="mock"&gt;移除mock &lt;a href="#mock" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="vueconfigjsbefore-requiremockmock-serverjs"&gt;vue.config.js删除before: require(&amp;rsquo;./mock/mock-server.js') &lt;a href="#vueconfigjsbefore-requiremockmock-serverjs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0dc3f94" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;module.exports = {
 publicPath: &amp;#39;/&amp;#39;,
 outputDir: &amp;#39;dist&amp;#39;,
 assetsDir: &amp;#39;static&amp;#39;,
 lintOnSave: process.env.NODE_ENV === &amp;#39;development&amp;#39;,
 productionSourceMap: false,
 devServer: {
 port: port,
 overlay: {
 warnings: false,
 errors: true
 }
 before: require(&amp;#39;./mock/mock-server.js&amp;#39;) //删除
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="mainjs"&gt;删除main.js如下代码 &lt;a href="#mainjs" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ba6b2b0" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { mockXHR } from &amp;#39;../mock&amp;#39;
if (process.env.NODE_ENV === &amp;#39;production&amp;#39;) {
 mockXHR()
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="api"&gt;修改api的接口为后端真实接口 &lt;a href="#api" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3999497" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// api/user.js
export function login(data) {
 return request({
 url: &amp;#39;/api/user/login&amp;#39;,
 method: &amp;#39;post&amp;#39;,
 data
 })
}

export function getInfo(token) {
 return request({
 url: &amp;#39;/api/user/getInfo&amp;#39;,
 method: &amp;#39;get&amp;#39;,
 params: { token }
 })
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="axiosbaseurl"&gt;修改axios的baseURL为后端地址 &lt;a href="#axiosbaseurl" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2cc9d8a" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// .env.development
VUE_APP_BASE_API = &amp;#39;http://localhost:8101/&amp;#39;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="axiosrequest"&gt;修改封装axios的request请求 &lt;a href="#axiosrequest" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9818ecd" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// create an axios instance
const service = axios.create({
 baseURL: process.env.VUE_APP_BASE_API, // url = base url &amp;#43; request url
 withCredentials: true, // send cookies when cross-domain requests
 timeout: 5000 // request timeout
})

//axios响应拦截器
 if (res.code !== 0) {
 Message({
 message: res.message || &amp;#39;Error&amp;#39;,
 type: &amp;#39;error&amp;#39;,
 duration: 5 * 1000
 })

 // 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
 if (res.code === 40100) {
 // to re-login
 MessageBox.confirm(&amp;#39;登录超时&amp;#39;, &amp;#39;Confirm logout&amp;#39;, {
 confirmButtonText: &amp;#39;确定&amp;#39;,
 cancelButtonText: &amp;#39;取消&amp;#39;,
 type: &amp;#39;warning&amp;#39;
 }).then(() =&amp;gt; {
 store.dispatch(&amp;#39;user/resetToken&amp;#39;).then(() =&amp;gt; {
 location.reload()
 })
 })
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="-storemodulesuser"&gt;修改 /store/modules/user的请求,将请求字段跟后端一致 &lt;a href="#-storemodulesuser" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5e62090" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; // user login
 login({ commit }, userInfo) {
 const { userAccount, userPassword } = userInfo
 return new Promise((resolve, reject) =&amp;gt; {
 login({ userAccount: userAccount.trim(), userPassword: userPassword }).then(response =&amp;gt; {
 const { data } = response
 commit(&amp;#39;SET_TOKEN&amp;#39;, data.token)
 setToken(data.token)
 resolve()
 }).catch(error =&amp;gt; {
 reject(error)
 })
 })
 },

 // get user info
 getInfo({ commit, state }) {
 return new Promise((resolve, reject) =&amp;gt; {
 getInfo(state.token).then(response =&amp;gt; {
 const { data } = response

 if (!data) {
 reject(&amp;#39;Verification failed, please Login again.&amp;#39;)
 }

 const { userRole, userName, userAvatar, userProfile } = data

 // roles must be a non-empty array
 if (!userRole || userRole.length &amp;lt;= 0) {
 reject(&amp;#39;getInfo: roles must be a non-null array!&amp;#39;)
 }

 commit(&amp;#39;SET_ROLES&amp;#39;, userRole)
 commit(&amp;#39;SET_NAME&amp;#39;, userName)
 commit(&amp;#39;SET_AVATAR&amp;#39;, userAvatar)
 commit(&amp;#39;SET_INTRODUCTION&amp;#39;, userProfile)
 resolve(data)
 }).catch(error =&amp;gt; {
 reject(error)
 })
 })
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="storegetter"&gt;修改store/getter字段与后端一致 &lt;a href="#storegetter" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7c60106" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; userAvatar: state =&amp;gt; state.user.userAvatar,
 userName: state =&amp;gt; state.user.userName,
 userProfile: state =&amp;gt; state.user.userProfile,
 userRole: state =&amp;gt; state.user.userRole,&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="permission"&gt;修改permission如下两处 &lt;a href="#permission" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="feef91a" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; if (hasToken) {
 if (to.path === &amp;#39;/login&amp;#39;) {
 next({ path: &amp;#39;/&amp;#39; })
 NProgress.done()
 } else {
 const hasRoles = store.getters.userRole &amp;amp;&amp;amp; store.getters.userRole.length &amp;gt; 0
 if (hasRoles) {
 next()
 } else {
 try {
 //将原本的roles改成userRole，跟后端一致
 const { userRole } = await store.dispatch(&amp;#39;user/getInfo&amp;#39;)

 const accessRoutes = await store.dispatch(&amp;#39;permission/generateRoutes&amp;#39;, userRole)

 router.addRoutes(accessRoutes)
 next({ ...to, replace: true })
 } catch (error) {
 await store.dispatch(&amp;#39;user/resetToken&amp;#39;)
 // 将error改成error.message
 Message.error(error.message || &amp;#39;Has Error&amp;#39;)
 next(`/login?redirect=${to.path}`)
 NProgress.done()
 }
 
 &lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="loginindexvue"&gt;修改login/index.vue &lt;a href="#loginindexvue" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;9.1 将账号密码请求字段与对应输入框ref字段改成userAccount，userPassword&lt;/p&gt;</description></item><item><title>el-upload封装</title><link>https://xiaoying.org.cn/pages/bfa4fd/</link><pubDate>Fri, 25 Aug 2023 11:15:42 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bfa4fd/</guid><description>&lt;p&gt;父组件模板&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ce16719" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;upload-component @file-selected=&amp;#34;handleFileSelected&amp;#34;&amp;gt;&amp;lt;/upload-component&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
import UploadComponent from &amp;#39;./UploadComponent.vue&amp;#39;;

export default {
 components: {
 UploadComponent
 },
 methods: {
 handleFileSelected(file) {
 // 处理选中的文件
 console.log(&amp;#39;选中的文件：&amp;#39;, file);
 // 执行其他逻辑
 }
 }
};
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;子组件模板（UploadComponent.vue）&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a990bbd" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div&amp;gt;
 &amp;lt;el-upload
 class=&amp;#34;upload-demo&amp;#34;
 :action=&amp;#34;uploadUrl&amp;#34;
 :on-change=&amp;#34;handleFileChange&amp;#34;
 &amp;gt;
 &amp;lt;el-button slot=&amp;#34;trigger&amp;#34;&amp;gt;选取文件&amp;lt;/el-button&amp;gt;
 &amp;lt;el-button style=&amp;#34;margin-left: 10px;&amp;#34;&amp;gt;上传到服务器&amp;lt;/el-button&amp;gt;
 &amp;lt;/el-upload&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script&amp;gt;
export default {
 methods: {
 handleFileChange(file) {
 // 触发自定义事件将文件传递给父组件
 this.$emit(&amp;#39;file-selected&amp;#39;, file);
 }
 }
};
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;在子组件中，当文件发生变化时，通过&lt;code&gt;this.$emit&lt;/code&gt;方法触发&lt;code&gt;file-selected&lt;/code&gt;事件，并将文件作为参数传递给父组件。&lt;/p&gt;</description></item><item><title>文件上传</title><link>https://xiaoying.org.cn/pages/c62336/</link><pubDate>Fri, 25 Aug 2023 11:15:40 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c62336/</guid><description>&lt;h2 id="heading"&gt;自动上传 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="fdcc3ab" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;el-upload
 class=&amp;#34;upload-demo&amp;#34;
 :on-success=&amp;#34;handleSuccess&amp;#34; //上传成功后的回调
 :before-upload=&amp;#34;beforeUpload&amp;#34;
 action=&amp;#34;/api/file/upload&amp;#34; //上传地址
 data // 请求参数
 accept=&amp;#34;.jpeg, .jpg, .svg, .png, .webp&amp;#34;
 multiple
&amp;gt;
 &amp;lt;img :src=&amp;#34;imgUrl&amp;#34; v-if=&amp;#34;flag&amp;#34; style=&amp;#34;width: 100%&amp;#34; /&amp;gt;
 &amp;lt;i class=&amp;#34;el-icon-upload&amp;#34;/&amp;gt;
 &amp;lt;div class=&amp;#34;el-upload__text&amp;#34;&amp;gt;将文件拖到此处，或&amp;lt;em&amp;gt;点击上传&amp;lt;/em&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;el-upload__tip&amp;#34; slot=&amp;#34;tip&amp;#34; style=&amp;#34;color:red&amp;#34;&amp;gt;只能上传jpeg, jpg, svg, png,
 webp文件,且大小不超过1M
 &amp;lt;/div&amp;gt;
&amp;lt;/el-upload&amp;gt;
 
&amp;lt;script&amp;gt;
export default {
 data() {
 return {
 data: {
 &amp;#34;biz&amp;#34;: user_avatar
 }
 }
 }
}
&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;手动上传 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="829b53f" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;el-upload
 class=&amp;#34;upload-demo&amp;#34;
 :before-upload=&amp;#34;beforeUpload&amp;#34;
 :http-request=&amp;#34;upload&amp;#34; //手动上传
 drag
 action=&amp;#34;#&amp;#34; //手动上传随遍填，不可为空
 accept=&amp;#34;.jpeg, .jpg, .svg, .png, .webp&amp;#34;
 multiple
&amp;gt;
 &amp;lt;img :src=&amp;#34;imgUrl&amp;#34; v-if=&amp;#34;flag&amp;#34; style=&amp;#34;width: 100%&amp;#34; /&amp;gt;
 &amp;lt;i class=&amp;#34;el-icon-upload&amp;#34;/&amp;gt;
 &amp;lt;div class=&amp;#34;el-upload__text&amp;#34;&amp;gt;将文件拖到此处，或&amp;lt;em&amp;gt;点击上传&amp;lt;/em&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;el-upload__tip&amp;#34; slot=&amp;#34;tip&amp;#34; style=&amp;#34;color:red&amp;#34;&amp;gt;只能上传jpeg, jpg, svg, png,
 webp文件,且大小不超过1M
 &amp;lt;/div&amp;gt;
&amp;lt;/el-upload&amp;gt;

async upload() {
 const formData = new FormData()
 formData.append(&amp;#39;file&amp;#39;, this.file)
 formData.append(&amp;#39;biz&amp;#39;, &amp;#39;user_avatar&amp;#39;)
 await changeAvatar(formData).then(res =&amp;gt; {
 this.flag = true
 this.form.avatar = res.data
 this.imgUrl = res.data
 })
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;上传前更改文件名 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7502369" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 先获取到源文件的后缀名，然后新建一个文件，将文件名改为时间戳加后缀名，防止名称重复，最后把新文件作为参数进行上传
**/
beforeUpload(file) {
 const fileExtension = file.name.split(&amp;#39;.&amp;#39;).pop().toLowerCase()
 const timeStamp = new Date().getTime()
 const copyFile = new File([file], `${timeStamp}` &amp;#43; &amp;#39;.&amp;#39; &amp;#43; fileExtension)
 this.file = copyFile
 },&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>mavon-editor局部引入</title><link>https://xiaoying.org.cn/pages/a252bf/</link><pubDate>Fri, 25 Aug 2023 11:15:41 +0000</pubDate><guid>https://xiaoying.org.cn/pages/a252bf/</guid><description>&lt;p&gt;editor.vue&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6775178" class="language-html wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
 &amp;lt;div id=&amp;#34;editor&amp;#34;&amp;gt;
 &amp;lt;mavon-editor style=&amp;#34;height: 100%&amp;#34;&amp;gt;&amp;lt;/mavon-editor&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;
&amp;lt;script&amp;gt;
// Local Registration
import { mavonEditor } from &amp;#39;mavon-editor&amp;#39;
import &amp;#39;mavon-editor/dist/css/index.css&amp;#39;
export default {
 name: &amp;#39;editor&amp;#39;,
 components: {
 mavonEditor
 // or &amp;#39;mavon-editor&amp;#39;: mavonEditor
 }
}
&amp;lt;/script&amp;gt;
&amp;lt;style&amp;gt;
#editor {
 margin: auto;
 width: 80%;
 height: 580px;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;main.js&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3e70b80" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import Vue from &amp;#39;vue&amp;#39;;
 var editor = require(&amp;#39;./editor.vue&amp;#39;);
 new Vue({
 el: &amp;#39;#main&amp;#39;,
 render: h =&amp;gt; h(editor)
});&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;将文件名与文件路径插入当前光标位置，这是mavon-editor 内置的方法&lt;/p&gt;</description></item><item><title>vuex使用</title><link>https://xiaoying.org.cn/pages/496006/</link><pubDate>Fri, 25 Aug 2023 11:15:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/496006/</guid><description>&lt;p&gt;::: info 总体流程&lt;/p&gt;
&lt;p&gt;store =&amp;gt; mutation =&amp;gt; action =&amp;gt; 组件内this.$store.dispatch()调用(非async异步)&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;store&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="394381f" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; const getters = {
 token: state =&amp;gt; state.user.token,
 userAvatar: state =&amp;gt; state.user.userAvatar,
 userProfile: state =&amp;gt; state.user.userProfile
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;mutation&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="225cb2b" class="language-js wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;const mutations = {
 SET_TOKEN: (state, token) =&amp;gt; {
 state.token = token
 },
 SET_PROFILE: (state, userProfile) =&amp;gt; {
 state.userProfile = userProfile
 },
 SET_AVATAR: (state, userAvatar) =&amp;gt; {
 state.userAvatar = userAvatar
 },
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;action&lt;/p&gt;</description></item><item><title>注意事项</title><link>https://xiaoying.org.cn/pages/de7220/</link><pubDate>Thu, 24 Aug 2023 14:21:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/de7220/</guid><description>&lt;h2 id="setupthis"&gt;setup不能使用this &lt;a href="#setupthis" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="0ad97a5" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import { useRouter } from &amp;#34;vue-router&amp;#34;
const router = useRouter() 
router.push(&amp;#39;/&amp;#39;) //相当于this.$router.push(&amp;#39;/&amp;#39;)

import { useRoute } from &amp;#34;vue-router&amp;#34;
const route = useRoute() //route是页面的路由信息，相当于this.$route&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;题目详情页 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="07285eb" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; &amp;lt;router-link :to=&amp;#34;&amp;#39;/interface/detail/&amp;#39;&amp;#43;item.id&amp;#34;&amp;gt;&amp;lt;/router-link&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="props"&gt;子组件props &lt;a href="#props" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ba76238" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;const props = defineProps({
 page: {
 type: Number,
 default: 1,
 },
 limit: {
 type: Number,
 default: 10,
 }
});

const emit = defineEmits([&amp;#34;pagination&amp;#34;, &amp;#34;update:page&amp;#34;, &amp;#34;update:limit&amp;#34;]);

const currentPage = useVModel(props, &amp;#34;page&amp;#34;, emit);

const pageSize = useVModel(props, &amp;#34;limit&amp;#34;, emit);

function handleSizeChange(val: number) {
 emit(&amp;#34;pagination&amp;#34;, { page: currentPage, limit: val });
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="-uncaught-typeerror-cannot-read-properties-of-null-reading-isce-at-renderslot"&gt;报错 Uncaught TypeError: Cannot read properties of null (reading ‘isCE‘) at renderSlot &lt;a href="#-uncaught-typeerror-cannot-read-properties-of-null-reading-isce-at-renderslot" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202401191405405.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202401191405405.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202401191405405.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202401191405405.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202401191405405.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202401191405405.png?w=2400 2400w
 " sizes="100vw" alt="" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>swagger自动生成接口</title><link>https://xiaoying.org.cn/pages/e2e95f/</link><pubDate>Thu, 24 Aug 2023 14:21:56 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e2e95f/</guid><description>&lt;h2 id="jsts"&gt;生成js/ts接口代码 &lt;a href="#jsts" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;github地址： &lt;a href="https://github.com/zeronejs/zerone" rel="external" target="_blank"&gt;https://github.com/zeronejs/zerone&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;官方文档地址：https://zerone.top/guide/cli.html#api&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h3 id="heading"&gt;安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b485331" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm i @zeronejs/cli --save-dev&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="swaggerconfigjsonsrcapi"&gt;编写swagger.config.json放置在src/api中 &lt;a href="#swaggerconfigjsonsrcapi" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7af9a67" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;{
 &amp;#34;docsUrl&amp;#34;: &amp;#34;http://www.example.com/v3/api-docs&amp;#34;, //json文档地址
 &amp;#34;includeTags&amp;#34;: [], //要包含的标签（未填充或空数组表示全部包含）
 &amp;#34;excludeTags&amp;#34;: [&amp;#34;bot-callback-controller&amp;#34;], //要排除的标签
 &amp;#34;axiosInstanceUrl&amp;#34;: &amp;#34;@/utils/request&amp;#34;, //axios实例地址（默认：@/utils/request）
 &amp;#34;prefix&amp;#34;: &amp;#34;api&amp;#34; //接口添加的前缀
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-1"&gt;运行命令生成代码 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5cd4dc7" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;//package.json
&amp;#34;scripts&amp;#34;: {
 &amp;#34;OpenAPI&amp;#34;: &amp;#34;zerone api -p ./src/api -d -js&amp;#34;
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;::: info 提示&lt;/p&gt;</description></item><item><title>动态路由</title><link>https://xiaoying.org.cn/pages/737d27/</link><pubDate>Thu, 24 Aug 2023 14:21:58 +0000</pubDate><guid>https://xiaoying.org.cn/pages/737d27/</guid><description>&lt;blockquote&gt;
 &lt;h3 id="heading"&gt;具体实现 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;创建vue实例的时候将vue-router挂载，但这个时候vue-router挂载一些登录或者不用权限的公用的页面。&lt;/li&gt;
&lt;li&gt;当用户登录后，获取用role，将role和路由表每个页面的需要的权限作比较，生成最终用户可访问的路由表。&lt;/li&gt;
&lt;li&gt;调用router.addRoute(route)添加用户可访问的路由。&lt;/li&gt;
&lt;li&gt;使用pinia管理路由表，根据vuex中可访问的路由渲染侧边栏组件。&lt;/li&gt;
&lt;/ol&gt;

 &lt;/blockquote&gt;
&lt;h2 id="heading-1"&gt;路由文件分静态路由和动态路由 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b175d73" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;export const constantRoutes: RouteRecordRaw[] = [
 {
 path: &amp;#34;/redirect&amp;#34;,
 component: Layout,
 meta: { hidden: true },
 children: [
 {
 path: &amp;#34;/redirect/:path(.*)&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/redirect/index.vue&amp;#34;),
 },
 ],
 },

 {
 path: &amp;#34;/login&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/login/index.vue&amp;#34;),
 meta: { hidden: true },
 },

 {
 path: &amp;#34;/&amp;#34;,
 component: Layout,
 redirect: &amp;#34;/dashboard&amp;#34;,
 children: [
 {
 path: &amp;#34;dashboard&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/dashboard/index.vue&amp;#34;),
 name: &amp;#34;Dashboard&amp;#34;,
 meta: { title: &amp;#34;dashboard&amp;#34;, icon: &amp;#34;homepage&amp;#34;, affix: true },
 },
 {
 path: &amp;#34;401&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/error-page/401.vue&amp;#34;),
 meta: { hidden: true },
 },
 {
 path: &amp;#34;404&amp;#34;,
 component: () =&amp;gt; import(&amp;#34;@/views/error-page/404.vue&amp;#34;),
 meta: { hidden: true },
 },
 ],
 }
];

// 动态路由
export const asyncRoute: RouteRecordRaw[] = [
 // 多级嵌套路由
 {
 path: &amp;#39;/nested&amp;#39;,
 component: Layout,
 redirect: &amp;#39;/nested/level1/level2&amp;#39;,
 name: &amp;#39;Nested&amp;#39;,
 meta: {title: &amp;#39;多级菜单&amp;#39;, icon: &amp;#39;nested&amp;#39;, userRole: [&amp;#39;user&amp;#39;]},
 children: [
 {
 path: &amp;#39;level1&amp;#39;,
 component: () =&amp;gt; import(&amp;#39;@/views/nested/level1/index.vue&amp;#39;),
 name: &amp;#39;Level1&amp;#39;,
 meta: {title: &amp;#39;菜单一级&amp;#39;,userRole: [&amp;#39;user&amp;#39;]},
 redirect: &amp;#39;/nested/level1/level2&amp;#39;,
 children: [
 {
 path: &amp;#39;level2&amp;#39;,
 component: () =&amp;gt; import(&amp;#39;@/views/nested/level1/level2/index.vue&amp;#39;),
 name: &amp;#39;Level2&amp;#39;,
 meta: {title: &amp;#39;菜单二级&amp;#39;,userRole: [&amp;#39;user&amp;#39;]},
 redirect: &amp;#39;/nested/level1/level2/level3&amp;#39;,
 children: [
 {
 path: &amp;#39;level3-1&amp;#39;,
 component: () =&amp;gt; import(&amp;#39;@/views/nested/level1/level2/level3/index1.vue&amp;#39;),
 name: &amp;#39;Level3-1&amp;#39;,
 meta: {title: &amp;#39;菜单三级-1&amp;#39;, userRole: [&amp;#34;admin&amp;#34;]}
 },
 {
 path: &amp;#39;level3-2&amp;#39;,
 component: () =&amp;gt; import(&amp;#39;@/views/nested/level1/level2/level3/index2.vue&amp;#39;),
 name: &amp;#39;Level3-2&amp;#39;,
 meta: {title: &amp;#39;菜单三级-2&amp;#39;, userRole: [&amp;#34;admin&amp;#34;]}
 }
 ]
 }
 ]
 },
 ]
 },
 // 外部链接
 {
	path: &amp;#39;/external-link&amp;#39;,
	component: Layout,
	name: &amp;#34;blogs&amp;#34;,
	meta: {title: &amp;#39;外部链接&amp;#39;, icon: &amp;#39;nested&amp;#39;, userRole: [&amp;#39;user&amp;#39;]},
	redirect: &amp;#39;https://www.cnblogs.com/haoxianrui/&amp;#39;,
	children: [
	 {
		path: &amp;#39;https://www.cnblogs.com/haoxianrui/&amp;#39;,
		name: &amp;#39;link&amp;#39;,
		meta: { title: &amp;#39;有来技术官方博客&amp;#39;, icon: &amp;#39;link&amp;#39;, userRole: [&amp;#39;user&amp;#39;] },
		redirect: &amp;#39;https://www.cnblogs.com/haoxianrui/&amp;#39;,
	 }
	]
 }
]&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;初始挂载静态路由 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;router.ts&lt;/p&gt;</description></item><item><title>整合 Element Plus</title><link>https://xiaoying.org.cn/pages/6a9e6c/</link><pubDate>Thu, 24 Aug 2023 14:22:03 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6a9e6c/</guid><description>&lt;h2 id="unplugin-"&gt;unplugin 自动导入 &lt;a href="#unplugin-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Element Plus 官方文档中推荐 &lt;code&gt;按需自动导入&lt;/code&gt; 的方式，而此需要使用额外的插件 &lt;code&gt;unplugin-auto-import&lt;/code&gt; 和 &lt;code&gt;unplugin-vue-components&lt;/code&gt; 来导入要使用的组件。所以在整合 &lt;code&gt;Element Plus&lt;/code&gt; 之前先了解下&lt;code&gt;自动导入&lt;/code&gt;的概念和作用&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;概念&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;为了避免在多个页面重复引入 &lt;code&gt;API&lt;/code&gt; 或 &lt;code&gt;组件&lt;/code&gt;，由此而产生的自动导入插件来节省重复代码和提高开发效率。&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;插件&lt;/th&gt;
 &lt;th&gt;概念&lt;/th&gt;
 &lt;th&gt;自动导入对象&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;unplugin-auto-import&lt;/td&gt;
 &lt;td&gt;按需自动导入API&lt;/td&gt;
 &lt;td&gt;ref，reactive,watch,computed 等API&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;unplugin-vue-components&lt;/td&gt;
 &lt;td&gt;按需自动导入组件&lt;/td&gt;
 &lt;td&gt;Element Plus 等三方库和指定目录下的自定义组件&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;看下自动导入插件未使用和使用的区别：&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;插件名&lt;/th&gt;
 &lt;th&gt;未使用自动导入&lt;/th&gt;
 &lt;th&gt;使用自动导入&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;unplugin-auto-import&lt;/td&gt;
 &lt;td&gt;










 &lt;img class="post-image zoomable" src="https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=1600" srcset="
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=480 480w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=768 768w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=1024 1024w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=1600 1600w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1.30miixfqejo0.webp?w=2400 2400w
 " sizes="100vw" alt="ff113799c83343acab22cbf0e810446atplv-k3u1fbpfcp-zoom-1" loading="lazy"&gt;


&lt;/td&gt;
 &lt;td&gt;










 &lt;img class="post-image zoomable" src="https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=1600" srcset="
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=480 480w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=768 768w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=1024 1024w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=1600 1600w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1.5dqt9hqqbhs0.webp?w=2400 2400w
 " sizes="100vw" alt="a78ddb9ff09e44afb96b45527ad719datplv-k3u1fbpfcp-zoom-1" loading="lazy"&gt;


&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;unplugin-vue-components&lt;/td&gt;
 &lt;td&gt;










 &lt;img class="post-image zoomable" src="https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=1600" srcset="
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=480 480w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=768 768w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=1024 1024w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=1600 1600w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1.17q5sa9mgd8g.webp?w=2400 2400w
 " sizes="100vw" alt="f1aeff2ce05346faa343eb9f1a796ebetplv-k3u1fbpfcp-zoom-1" loading="lazy"&gt;


&lt;/td&gt;
 &lt;td&gt;










 &lt;img class="post-image zoomable" src="https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=1600" srcset="
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=480 480w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=768 768w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=1024 1024w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=1600 1600w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1.2xbo2fzgkhe0.webp?w=2400 2400w
 " sizes="100vw" alt="f8b9af5a27684af59d32338992a200cbtplv-k3u1fbpfcp-zoom-1" loading="lazy"&gt;


&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;安装插件依赖&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>wangeditor使用</title><link>https://xiaoying.org.cn/pages/42c07b/</link><pubDate>Thu, 24 Aug 2023 14:22:01 +0000</pubDate><guid>https://xiaoying.org.cn/pages/42c07b/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;安装及使用&lt;a href="https://www.wangeditor.com/v5/for-frame.html#vue3" rel="external" target="_blank"&gt;https://www.wangeditor.com/v5/for-frame.html#vue3&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="heading"&gt;工具栏配置 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="f3a5394" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;const toolbars = reactive({
 // excludeKeys为排除不想要的菜单，只需填写写菜单组 key 的值即可
 excludeKeys: [
 // 全部菜单如下所示
	&amp;#34;header1&amp;#34;,// 标题
	&amp;#34;header2&amp;#34;,
	&amp;#34;header3&amp;#34;,
	&amp;#34;|&amp;#34;,
	&amp;#34;blockquote&amp;#34;, // 引用
	&amp;#34;bold&amp;#34;, // 加粗
	&amp;#34;underline&amp;#34;, // 下划线
	&amp;#34;italic&amp;#34;, // 斜体
	&amp;#34;group-more-style&amp;#34;,
	&amp;#34;color&amp;#34;, // 文字颜色

	&amp;#34;bgColor&amp;#34;, // 背景色

	&amp;#34;fontSize&amp;#34;, // 字号

	&amp;#34;fontFamily&amp;#34;, // 字体

	&amp;#34;lineHeight&amp;#34;, // 行高

	&amp;#34;bulletedList&amp;#34;, // 无序列表

	&amp;#34;numberedList&amp;#34;, // 有序列表
	
	&amp;#34;justifyLeft&amp;#34;, //左对齐
	
	&amp;#34;justifyRight&amp;#34;, //右对齐
	
 &amp;#34;justifyCenter&amp;#34;, //居中对齐

	&amp;#34;todo&amp;#34;, // 代办
	
	&amp;#34;emotion&amp;#34;,// 表情
	
	&amp;#34;insertLink&amp;#34;,// 插入链接
	
	&amp;#34;insertTable&amp;#34;,// 插入表格
	
	&amp;#34;codeBlock&amp;#34;, // 代码块
	
	&amp;#34;divider&amp;#34;, // 分割线
	
	&amp;#34;undo&amp;#34;, // 撤销
	
	&amp;#34;redo&amp;#34;, // 重做
	
	&amp;#34;fullScreen&amp;#34;, // 全屏
	
	&amp;#34;through&amp;#34;, //中划线
	
	&amp;#34;clearStyle&amp;#34; , //清除格式
	
	&amp;#34;group-indent&amp;#34;, // 缩进
	
	&amp;#34;group-image&amp;#34;, // 上传图片
	
	&amp;#34;insertVideo&amp;#34; // 上传视频
 ]
})&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;图片及视频上传 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4336fcb" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 编辑器配置
const editorConfig = ref({
	placeholder: &amp;#34;请输入内容...&amp;#34;,
 autoFocus : false,
 readOnly: props.readOnly,
	MENU_CONF: {
		uploadImage: {
			// 自定义图片上传
			async customUpload(file: any, insertFn: any) {
				uploadFileApi(file).then((response) =&amp;gt; {
					const url = response.data;
					insertFn(url);
				});
			},
		},
		uploadVideo: {
		 // 自定义视频上传
		 async customUpload(file: any, insertFn: any) { // TS 语法
			uploadVideoApi(file).then((response) =&amp;gt; {
				 const url = response.data;
				 insertFn(url);
			 });
		 }
		}
	},
});


//uploadApi接口如下

/**
 * 上传视频
 *
 * @param file
 */
export function uploadVideoApi(file: File): AxiosPromise&amp;lt;FileInfo&amp;gt; {
 const formData = new FormData();
 formData.append(&amp;#39;file&amp;#39;, file);
 formData.append(&amp;#39;biz&amp;#39;, &amp;#39;file&amp;#39;);
 return request({
	url: &amp;#39;/api/file/upload&amp;#39;,
	method: &amp;#39;post&amp;#39;,
	data: formData,
	headers: {
	 &amp;#39;Content-Type&amp;#39;: &amp;#39;multipart/form-data&amp;#39;
	}
 });
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>monacoEditor使用</title><link>https://xiaoying.org.cn/pages/cf91ad/</link><pubDate>Thu, 24 Aug 2023 14:22:02 +0000</pubDate><guid>https://xiaoying.org.cn/pages/cf91ad/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;基于vue3 + vite4 + element-plus
官网： &lt;a href="https://github.com/microsoft/monaco-editor" rel="external" target="_blank"&gt;https://github.com/microsoft/monaco-editor&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;
演示： &lt;a href="https://microsoft.github.io/monaco-editor/playground.html?source=v0.40.0#example-creating-the-editor-hello-world" rel="external" target="_blank"&gt;https://microsoft.github.io/monaco-editor/playground.html?source=v0.40.0#example-creating-the-editor-hello-world&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>自定义404页面</title><link>https://xiaoying.org.cn/pages/601046/</link><pubDate>Thu, 24 Aug 2023 14:22:07 +0000</pubDate><guid>https://xiaoying.org.cn/pages/601046/</guid><description>&lt;h2 id="vue2"&gt;vue2 &lt;a href="#vue2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a11dd42" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;script&amp;gt;
export default {
 data() {
	return {
	 message: &amp;#34;阿噢，一不小心来到了荒无人烟的沙漠&amp;#34;
	};
 }
};
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;wscn-http404-container&amp;#34;&amp;gt;
	&amp;lt;div class=&amp;#34;wscn-http404&amp;#34;&amp;gt;
	 &amp;lt;div class=&amp;#34;pic-404&amp;#34;&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__parent&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012125958.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child left&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child mid&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child right&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
	 &amp;lt;/div&amp;gt;
	 &amp;lt;div class=&amp;#34;bullshit&amp;#34;&amp;gt;
		&amp;lt;div class=&amp;#34;bullshit__oops&amp;#34;&amp;gt;OOPS!&amp;lt;/div&amp;gt;
		&amp;lt;div class=&amp;#34;bullshit__info&amp;#34;&amp;gt;
		 All rights reserved
		 &amp;lt;a
			style=&amp;#34;color: #20a0ff&amp;#34;
			href=&amp;#34;https://vuepress.vuejs.org/zh/theme/option-api.html#globallayout&amp;#34;
			target=&amp;#34;_blank&amp;#34;
		 &amp;gt;vuepress&amp;lt;/a
		 &amp;gt;
		&amp;lt;/div&amp;gt;
		&amp;lt;div class=&amp;#34;bullshit__headline&amp;#34;&amp;gt;{{ message }}&amp;lt;/div&amp;gt;
		&amp;lt;div class=&amp;#34;bullshit__info&amp;#34;&amp;gt;
		 请检查您输入的网址是否正确，或返回首页。
		&amp;lt;/div&amp;gt;
		&amp;lt;a href=&amp;#34;/&amp;#34; class=&amp;#34;bullshit__return-home&amp;#34;&amp;gt;回首页&amp;lt;/a&amp;gt;
	 &amp;lt;/div&amp;gt;
	&amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style lang=&amp;#34;stylus&amp;#34; scoped&amp;gt;

.wscn-http404-container {
 position: relative !important;
}

.wscn-http404 {
 position: absolute !important;
 top: 50% !important;
 transform: translateY(50%) !important;
 width: 1200px;
 padding: 0 50px;
 overflow: hidden;
}

.wscn-http404 &amp;gt; .pic-404 {
 position: relative;
 float: left;
 width: 600px;
 overflow: hidden;
}

.pic-404__parent {
 width: 100%;
}

.pic-404__child {
 position: absolute;
}


.left {
 top: 17px;
 left: 220px;
 width: 80px;
 opacity: 0;
 animation-name: cloudLeft;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1s;
 animation-fill-mode: forwards;
}

 .mid {
 top: 10px;
 left: 420px;
 width: 46px;
 opacity: 0;
 animation-name: cloudMid;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1.2s;
 animation-fill-mode: forwards;
}

.right {
 top: 100px;
 left: 500px;
 width: 62px;
 opacity: 0;
 animation-name: cloudRight;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1s;
 animation-fill-mode: forwards;
}

@keyframes cloudLeft {
 0% {
	top: 17px;
	left: 220px;
	opacity: 0;
 }
 
 20% {
	top: 33px;
	left: 188px;
	opacity: 1;
 }
 
 80% {
	top: 81px;
	left: 92px;
	opacity: 1;
 }
 
 100% {
	top: 97px;
	left: 60px;
	opacity: 0;
 }
}

@keyframes cloudRight {
 0% {
	top: 100px;
	left: 500px;
	opacity: 0;
 }
 
 20% {
	top: 120px;
	left: 460px;
	opacity: 1;
 }
 
 80% {
	top: 180px;
	left: 340px;
	opacity: 1;
 }
 
 100% {
	top: 200px;
	left: 300px;
	opacity: 0;
 }
}

.bullshit {
 position: relative;
 float: left;
 width: 300px;
 padding: 30px 0;
 overflow: hidden;
}

.bullshit__oops {
 margin-bottom: 20px;
 font-size: 32px;
 font-weight: bold;
 line-height: 40px;
 color: #1482f0;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-fill-mode: forwards;
}

.bullshit__headline {
 margin-bottom: 10px;
 font-size: 20px;
 font-weight: bold;
 line-height: 24px;
 color: #222;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.1s;
 animation-fill-mode: forwards;
}

.bullshit__info {
 margin-bottom: 30px;
 font-size: 13px;
 line-height: 21px;
 color: grey;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.2s;
 animation-fill-mode: forwards;
}

.bullshit__return-home {
 display: block;
 float: left;
 width: 110px;
 height: 36px;
 font-size: 14px;
 line-height: 36px;
 color: #fff;
 text-align: center;
 cursor: pointer;
 background: #1482f0;
 border-radius: 100px;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.3s;
 animation-fill-mode: forwards;
}

@keyframes slideUp {
 0% {
	opacity: 0;
	transform: translateY(60px);
 }
 
 100% {
	opacity: 1;
	transform: translateY(0);
 }
}


&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="vue3"&gt;vue3 &lt;a href="#vue3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="098dfb6" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- setup 无法设置组件名称，组件名称keepAlive必须 --&amp;gt;
&amp;lt;script lang=&amp;#34;ts&amp;#34;&amp;gt;
export default {
 name: &amp;#34;Page404&amp;#34;,
};
&amp;lt;/script&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
const message = &amp;#34;当前页面不存在&amp;#34;
&amp;lt;/script&amp;gt;

&amp;lt;template&amp;gt;
 &amp;lt;div class=&amp;#34;wscn-http404-container&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;wscn-http404&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;pic-404&amp;#34;&amp;gt;
 &amp;lt;img
		 class=&amp;#34;pic-404__parent&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012125958.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child left&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child mid&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
		&amp;lt;img
		 class=&amp;#34;pic-404__child right&amp;#34;
		 src=&amp;#34;https://img.xiaoying.org.cn/img/202310012126428.png
		 alt=&amp;#34;404&amp;#34;
		/&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;bullshit&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;bullshit__oops&amp;#34;&amp;gt;OOPS!&amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;bullshit__info&amp;#34;&amp;gt;
 All rights reserved
 &amp;lt;a
 style=&amp;#34;color: #20a0ff&amp;#34;
 href=&amp;#34;https://wallstreetcn.com&amp;#34;
 target=&amp;#34;_blank&amp;#34;
 &amp;gt;wallstreetcn&amp;lt;/a
 &amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;bullshit__headline&amp;#34;&amp;gt;{{ message }}&amp;lt;/div&amp;gt;
 &amp;lt;div class=&amp;#34;bullshit__info&amp;#34;&amp;gt;
					 请检查您输入的网址是否正确，或返回首页。
 &amp;lt;/div&amp;gt;
 &amp;lt;a href=&amp;#34;&amp;#34; class=&amp;#34;bullshit__return-home&amp;#34;&amp;gt;回首页&amp;lt;/a&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;style lang=&amp;#34;scss&amp;#34; scoped&amp;gt;
.wscn-http404-container {
 position: absolute;
 top: 40%;
 left: 50%;
 transform: translate(-50%, -50%);
}

.wscn-http404 {
 position: relative;
 width: 1200px;
 padding: 0 50px;
 overflow: hidden;

 .pic-404 {
 position: relative;
 float: left;
 width: 600px;
 overflow: hidden;

 &amp;amp;__parent {
 width: 100%;
 }

 &amp;amp;__child {
 position: absolute;

 &amp;amp;.left {
 top: 17px;
 left: 220px;
 width: 80px;
 opacity: 0;
 animation-name: cloudLeft;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1s;
 animation-fill-mode: forwards;
 }

 &amp;amp;.mid {
 top: 10px;
 left: 420px;
 width: 46px;
 opacity: 0;
 animation-name: cloudMid;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1.2s;
 animation-fill-mode: forwards;
 }

 &amp;amp;.right {
 top: 100px;
 left: 500px;
 width: 62px;
 opacity: 0;
 animation-name: cloudRight;
 animation-duration: 2s;
 animation-timing-function: linear;
 animation-delay: 1s;
 animation-fill-mode: forwards;
 }

 @keyframes cloudLeft {
 0% {
 top: 17px;
 left: 220px;
 opacity: 0;
 }

 20% {
 top: 33px;
 left: 188px;
 opacity: 1;
 }

 80% {
 top: 81px;
 left: 92px;
 opacity: 1;
 }

 100% {
 top: 97px;
 left: 60px;
 opacity: 0;
 }
 }

 @keyframes cloudMid {
 0% {
 top: 10px;
 left: 420px;
 opacity: 0;
 }

 20% {
 top: 40px;
 left: 360px;
 opacity: 1;
 }

 70% {
 top: 130px;
 left: 180px;
 opacity: 1;
 }

 100% {
 top: 160px;
 left: 120px;
 opacity: 0;
 }
 }

 @keyframes cloudRight {
 0% {
 top: 100px;
 left: 500px;
 opacity: 0;
 }

 20% {
 top: 120px;
 left: 460px;
 opacity: 1;
 }

 80% {
 top: 180px;
 left: 340px;
 opacity: 1;
 }

 100% {
 top: 200px;
 left: 300px;
 opacity: 0;
 }
 }
 }
 }

 .bullshit {
 position: relative;
 float: left;
 width: 300px;
 padding: 30px 0;
 overflow: hidden;

 &amp;amp;__oops {
 margin-bottom: 20px;
 font-size: 32px;
 font-weight: bold;
 line-height: 40px;
 color: #1482f0;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-fill-mode: forwards;
 }

 &amp;amp;__headline {
 margin-bottom: 10px;
 font-size: 20px;
 font-weight: bold;
 line-height: 24px;
 color: #222;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.1s;
 animation-fill-mode: forwards;
 }

 &amp;amp;__info {
 margin-bottom: 30px;
 font-size: 13px;
 line-height: 21px;
 color: grey;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.2s;
 animation-fill-mode: forwards;
 }

 &amp;amp;__return-home {
 display: block;
 float: left;
 width: 110px;
 height: 36px;
 font-size: 14px;
 line-height: 36px;
 color: #fff;
 text-align: center;
 cursor: pointer;
 background: #1482f0;
 border-radius: 100px;
 opacity: 0;
 animation-name: slideUp;
 animation-duration: 0.5s;
 animation-delay: 0.3s;
 animation-fill-mode: forwards;
 }

 @keyframes slideUp {
 0% {
 opacity: 0;
 transform: translateY(60px);
 }

 100% {
 opacity: 1;
 transform: translateY(0);
 }
 }
 }
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;相关图片 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=1600" srcset="
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=480 480w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=768 768w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=1024 1024w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=1600 1600w,
 https://jsd.cdn.zzko.cn/gh/liyao52033/picx-images-hosting@master/%e5%89%8d%e7%ab%af/404_cloud.7bq0ip52udc0.webp?w=2400 2400w
 " sizes="100vw" alt="404_cloud" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>验证码封装</title><link>https://xiaoying.org.cn/pages/33c2fd/</link><pubDate>Thu, 24 Aug 2023 15:16:11 +0000</pubDate><guid>https://xiaoying.org.cn/pages/33c2fd/</guid><description>&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7ca066e" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
	&amp;lt;el-form-item class=&amp;#34;login-container&amp;#34; prop=&amp;#34;verifyCode&amp;#34; label=&amp;#34;验证码&amp;#34;&amp;gt;
		&amp;lt;el-input
			v-model=&amp;#34;captchaData.verifyCode&amp;#34;
			auto-complete=&amp;#34;off&amp;#34;
			placeholder=&amp;#34;请输入右侧的计算结果&amp;#34;
			clearable
			class=&amp;#34;input&amp;#34;
			size=&amp;#34;large&amp;#34;
			@change=&amp;#34;verifyCaptcha&amp;#34;
			@input=&amp;#34;setVerifyCode&amp;#34;
		&amp;gt;
		 &amp;lt;template #prefix&amp;gt;
			&amp;lt;svg-icon icon-class=&amp;#34;verify_code&amp;#34;/&amp;gt;
		 &amp;lt;/template&amp;gt;
		&amp;lt;/el-input&amp;gt;
		&amp;lt;div class=&amp;#34;captcha&amp;#34;&amp;gt;
			&amp;lt;img :src=&amp;#34;captchaBase64&amp;#34; @click=&amp;#34;getCaptcha&amp;#34;/&amp;gt;
		&amp;lt;/div&amp;gt;
	&amp;lt;/el-form-item&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script lang=&amp;#34;ts&amp;#34; setup&amp;gt;

import SvgIcon from &amp;#34;@/components/SvgIcon/index.vue&amp;#34;;
import { getCaptchaApi } from &amp;#34;@/api/auth&amp;#34;;
import { CaptchaCheck, CaptchaControllerService } from &amp;#34;@/generated&amp;#34;;

const props = defineProps({
 verifyCode: {
	type: String,
	required: true
 },
 rules: {
	type: Object,
	required: true
 }
});


const emit = defineEmits([&amp;#39;update:verifyCode&amp;#39;]);

const setVerifyCode = (value: string) =&amp;gt; {
 emit(&amp;#39;update:verifyCode&amp;#39;, value); // 发送自定义事件更新父组件的 verifyCode 值
};

watch(() =&amp;gt; props.verifyCode, (newValue) =&amp;gt; {
 captchaData.value.verifyCode= newValue; // 当从父组件传来的 verifyCode 值变化时，更新本地的 verifyCode 值
});

/**
 * 验证码图片Base64字符串
 */
const captchaBase64 = ref();

const captchaData = ref&amp;lt;CaptchaCheck&amp;gt;({
	verifyCode: props.verifyCode,
	verifyCodeKey: &amp;#34;&amp;#34;,
});

let selfRules = ref({})
const veriflCode = [{
 validator: verifyCaptcha,
 trigger: &amp;#39;blur&amp;#39;
}]

/**
 * 获取验证码
 */
function getCaptcha() {
	getCaptchaApi().then(({ data }) =&amp;gt; {
		const { verifyCodeBase64, verifyCodeKey } = data;
		captchaData.value.verifyCodeKey = verifyCodeKey;
		captchaBase64.value = verifyCodeBase64;
	});
}

/**
 * 校验
 */
async function verifyCaptcha (rule: any, value: any, callback: any) {
 if (value){
	return new Promise((resolve, reject) =&amp;gt; {
	 CaptchaControllerService.checkCaptcha(captchaData.value)
		.then((res) =&amp;gt; {
		 const code = res.data
		 if (code !== value){
			callback(new Error(&amp;#39;验证码错误!&amp;#39;))
		 } else if(!code){
			callback(new Error(&amp;#39;验证码超时!&amp;#39;))
		 }else {
			callback()
		 }
		})
		.catch((error: any) =&amp;gt; {
		 reject(error);
		 getCaptcha();
		});
	})
 } else {
	callback(new Error(&amp;#39;验证码不能为空!&amp;#39;))
 }
}

onBeforeMount(() =&amp;gt; {
 selfRules.value = props.rules
 selfRules.value.verifyCode = veriflCode
})

onMounted(() =&amp;gt; {
	getCaptcha();
});

&amp;lt;/script&amp;gt;

&amp;lt;style lang=&amp;#34;scss&amp;#34; scoped&amp;gt;
:deep(.el-form-item__content){
 display: flex;
 flex-grow: 1;
 flex-wrap: nowrap;
 align-items: center;
 justify-content: left;
}

:deep(.el-form-item__label){
 height: 48px;
 line-height: 48px;
}

.login-container {
	width: 500px;
	//padding: 20px 35px 0;
	display: flex;
	white-space: nowrap;

	.input {
		background: transparent;
		height: 48px;
	 flex-grow: 1;

		// 子组件 scoped 无效，使用 :deep
		//:deep(.el-input__wrapper) {
		// padding: 0;
		// background: transparent;
		// box-shadow: none;
		//
		// .el-input__inner {
		//	color: #fff;
		//	background: transparent;
		//	border: 0;
		//	border-radius: 0;
		//	caret-color: #fff;
		//
		//	&amp;amp;:-webkit-autofill {
		//	 box-shadow: 0 0 0 1000px transparent inset !important;
		//	 -webkit-text-fill-color: #fff !important;
		//	}
		//
		//	// 设置输入框自动填充的延迟属性
		//	&amp;amp;:-webkit-autofill,
		//	&amp;amp;:-webkit-autofill:hover,
		//	&amp;amp;:-webkit-autofill:focus,
		//	&amp;amp;:-webkit-autofill:active {
		//	 transition: color 99999s ease-out, background-color 99999s ease-out;
		//	 transition-delay: 99999s;
		//	}
		// }
		//}
	}

	.captcha {
		margin-left: 1px;

		img {
		 width: 120px;
		 height: 48px;
		 cursor: pointer;
		 display: flex;
		 align-items: center;
		}
	}
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>联表查询SQL</title><link>https://xiaoying.org.cn/pages/a64fac/</link><pubDate>Thu, 24 Aug 2023 18:03:14 +0000</pubDate><guid>https://xiaoying.org.cn/pages/a64fac/</guid><description>&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a2e98a7" class="language-sql wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 用户分页列表 --&amp;gt;
 &amp;lt;select id=&amp;#34;getUserPage&amp;#34; resultType=&amp;#34;com.youlai.system.model.bo.UserBO&amp;#34;&amp;gt;
 SELECT
 u.id,
 u.username,
 u.nickname,
 u.mobile,
 u.gender,
 u.avatar,
 u.STATUS,
 d.NAME AS dept_name,
 GROUP_CONCAT( r.NAME ) AS roleNames,
 u.create_time
 FROM
 sys_user u
 LEFT JOIN sys_dept d ON u.dept_id = d.id
 LEFT JOIN sys_user_role sur ON u.id = sur.user_id
 LEFT JOIN sys_role r ON sur.role_id = r.id
 &amp;lt;where&amp;gt;
 u.deleted = 0 AND u.username != &amp;#39;root&amp;#39;
 &amp;lt;if test=&amp;#39;queryParams.keywords!=null and queryParams.keywords.trim() neq &amp;#34;&amp;#34;&amp;#39;&amp;gt;
 AND (
 u.username LIKE CONCAT(&amp;#39;%&amp;#39;,#{queryParams.keywords},&amp;#39;%&amp;#39;)
 OR u.nickname LIKE CONCAT(&amp;#39;%&amp;#39;,#{queryParams.keywords},&amp;#39;%&amp;#39;)
 OR u.mobile LIKE CONCAT(&amp;#39;%&amp;#39;,#{queryParams.keywords},&amp;#39;%&amp;#39;)
 )
 &amp;lt;/if&amp;gt;
 &amp;lt;if test=&amp;#39;queryParams.status!=null&amp;#39;&amp;gt;
 AND u.status = #{queryParams.status}
 &amp;lt;/if&amp;gt;
 &amp;lt;if test=&amp;#39;queryParams.deptId!=null&amp;#39;&amp;gt;
 AND concat(&amp;#39;,&amp;#39;,concat(d.tree_path,&amp;#39;,&amp;#39;,d.id),&amp;#39;,&amp;#39;) like concat(&amp;#39;%,&amp;#39;,#{queryParams.deptId},&amp;#39;,%&amp;#39;)
 &amp;lt;/if&amp;gt;
 &amp;lt;/where&amp;gt;
 GROUP BY u.id
 &amp;lt;/select&amp;gt;
 
 
 &amp;lt;!-- 获取路由列表 --&amp;gt;
 &amp;lt;select id=&amp;#34;listRoutes&amp;#34; resultMap=&amp;#34;RouteMap&amp;#34;&amp;gt;
 SELECT
 t1.id,
 t1.name,
 t1.parentId,
 t1.path,
 t1.component,
 t1.icon,
 t1.sort,
 t1.visible,
 t1.redirect,
 t1.type,
 t3.code
 FROM
 sys_menu t1
 LEFT JOIN sys_role_menu t2 ON t1.id = t2.menuId
 LEFT JOIN sys_role t3 ON t2.roleId = t3.id
 WHERE
 t1.type != &amp;#39;${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}&amp;#39;
 ORDER BY t1.sort asc
 &amp;lt;/select&amp;gt;

 &amp;lt;!-- 获取角色拥有的权限集合 --&amp;gt;
 &amp;lt;select id=&amp;#34;listRolePerms&amp;#34; resultType=&amp;#34;java.lang.String&amp;#34;&amp;gt;
 SELECT
 DISTINCT t1.perm
 FROM
 sys_menu t1
 INNER JOIN sys_role_menu t2 ON t1.id = t2.menuId
 INNER JOIN sys_role t3 ON t3.id = t2.roleId
 WHERE
 t1.type = &amp;#39;${@com.youlai.system.common.enums.MenuTypeEnum@BUTTON.getValue()}&amp;#39;
 AND t1.perm IS NOT NULL
 &amp;lt;choose&amp;gt;
 &amp;lt;when test=&amp;#34;roles!=null and roles.size()&amp;gt;0&amp;#34;&amp;gt;
 AND t3.CODE IN
 &amp;lt;foreach collection=&amp;#34;roles&amp;#34; item=&amp;#34;role&amp;#34; separator=&amp;#34;,&amp;#34; open=&amp;#34;(&amp;#34; close=&amp;#34;)&amp;#34;&amp;gt;
 #{role}
 &amp;lt;/foreach&amp;gt;
 &amp;lt;/when&amp;gt;
 &amp;lt;otherwise&amp;gt;
 AND t1.id = -1
 &amp;lt;/otherwise&amp;gt;
 &amp;lt;/choose&amp;gt;
 &amp;lt;/select&amp;gt;
 
&amp;lt;!-- 获取角色拥有的菜单ID集合 --&amp;gt;
 &amp;lt;select id=&amp;#34;listMenuIdsByRoleId&amp;#34; resultType=&amp;#34;java.lang.Long&amp;#34;&amp;gt;
 SELECT
 rm.menuId
 FROM
 sys_role_menu rm
 INNER JOIN sys_menu m ON rm.menuId = m.id
 WHERE
 rm.roleId = #{roleId}
 &amp;lt;/select&amp;gt;
 
 &amp;lt;!-- 获取用户导出列表 --&amp;gt;
 &amp;lt;select id=&amp;#34;listExportUsers&amp;#34; resultType=&amp;#34;com.youlai.system.model.vo.UserExportVO&amp;#34;&amp;gt;
 SELECT
 u.username,
 u.nickname,
 u.mobile,
 CASE u.gender
 WHEN 1 THEN &amp;#39;男&amp;#39;
 WHEN 2 THEN &amp;#39;女&amp;#39;
 ELSE &amp;#39;未知&amp;#39;
 END gender,
 d.NAME AS dept_name,
 u.createTime
 FROM
 sys_user u
 LEFT JOIN sys_dept d ON u.deptId = d.id
 &amp;lt;where&amp;gt;
 u.isDelete = 0 AND u.username != &amp;#39;root&amp;#39;
 &amp;lt;if test=&amp;#39;keywords!=null and keywords.trim() neq &amp;#34;&amp;#34;&amp;#39;&amp;gt;
 AND (u.username LIKE CONCAT(&amp;#39;%&amp;#39;,#{keywords},&amp;#39;%&amp;#39;)
 OR u.nickname LIKE CONCAT(&amp;#39;%&amp;#39;,#{keywords},&amp;#39;%&amp;#39;)
 OR u.mobile LIKE CONCAT(&amp;#39;%&amp;#39;,#{keywords},&amp;#39;%&amp;#39;))
 &amp;lt;/if&amp;gt;
 &amp;lt;if test=&amp;#39;status!=null&amp;#39;&amp;gt;
 AND u.status = #{status}
 &amp;lt;/if&amp;gt;
 &amp;lt;if test=&amp;#39;deptId!=null&amp;#39;&amp;gt;
 AND concat(&amp;#39;,&amp;#39;,concat(d.tree_path,&amp;#39;,&amp;#39;,d.id),&amp;#39;,&amp;#39;) like concat(&amp;#39;%,&amp;#39;,#{deptId},&amp;#39;,%&amp;#39;)
 &amp;lt;/if&amp;gt;
 &amp;lt;/where&amp;gt;
 GROUP BY u.id
 &amp;lt;/select&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>element-plus多文件手动上传</title><link>https://xiaoying.org.cn/pages/306c00/</link><pubDate>Sun, 03 Nov 2024 17:41:35 +0000</pubDate><guid>https://xiaoying.org.cn/pages/306c00/</guid><description>&lt;p&gt;::: info 提示&lt;/p&gt;
&lt;p&gt;http-request上传多文件会导致每个文件都会自动上传从而多次请求后端接口，设置auto-upload=false，然后再添加一个上传按钮来请求后端接口，只提交一次上传多个文件，上传成功后清除上传文件列表&lt;/p&gt;
&lt;p&gt;:::&lt;/p&gt;
&lt;p&gt;接口文件&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="782e5e2" class="language-ts wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 * 上传多个文件
 */
export function multipartUploadLicense(files: File[], onProgress: (progressEvent: ProgressEvent) =&amp;gt; void ): AxiosPromise&amp;lt;FileInfo&amp;gt; {
 const formData = new FormData();
	files.forEach((file) =&amp;gt; {
			formData.append(&amp;#39;files&amp;#39;, file);
	});
	//@ts-ignore
	return request({
		url: &amp;#34;/api/license/multipartUpload&amp;#34;,
		method: &amp;#34;post&amp;#34;,
		data: formData,
		onUploadProgress: onProgress, // 设置上传进度回调
		headers: {
			&amp;#34;Content-Type&amp;#34;: &amp;#34;multipart/form-data&amp;#34;,
		},
	});
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;vue文件&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="908c665" class="language-vue wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;template&amp;gt;
	&amp;lt;div&amp;gt;
		&amp;lt;el-upload
			ref=&amp;#34;uploadRef&amp;#34;
			v-model:file-list=&amp;#34;fileList&amp;#34;
			class=&amp;#34;upload-demo&amp;#34;
			drag
			action=&amp;#34;&amp;#34;
			accept=&amp;#34;.lic, .keystore&amp;#34;
			:before-upload=&amp;#34;beforeUpload&amp;#34;
			:on-change=&amp;#34;handleChange&amp;#34;
			multiple
			:limit=&amp;#34;2&amp;#34;
			:on-exceed=&amp;#34;handleExceed&amp;#34;
			:auto-upload=false
			style=&amp;#34;width: 50%;margin: 20px auto&amp;#34;
		&amp;gt;
			&amp;lt;el-icon class=&amp;#34;el-icon--upload&amp;#34;&amp;gt;&amp;lt;upload-filled /&amp;gt;&amp;lt;/el-icon&amp;gt;
			&amp;lt;div class=&amp;#34;el-upload__text&amp;#34;&amp;gt;
				拖拽或&amp;lt;em&amp;gt;点击上传&amp;lt;/em&amp;gt;
			&amp;lt;/div&amp;gt;
			&amp;lt;template #tip&amp;gt;
				&amp;lt;div class=&amp;#34;el-upload__tip&amp;#34; style=&amp;#34;color:red&amp;#34;&amp;gt;
					只能上传.lic和.keystore等授权文件，不能超过2个，每个大小不超2M
				&amp;lt;/div&amp;gt;
			&amp;lt;/template&amp;gt;
		&amp;lt;/el-upload&amp;gt;

		//进度条
		&amp;lt;el-progress
			v-if=&amp;#34;uploading&amp;#34;
			:percentage=&amp;#34;uploadProgress&amp;#34;
			:text-inside=&amp;#34;true&amp;#34;
			:stroke-width=&amp;#34;24&amp;#34;
			status=&amp;#34;success&amp;#34;
			style=&amp;#34;width: 80%;margin: 0 auto&amp;#34;
		/&amp;gt;

		&amp;lt;el-button type=&amp;#34;primary&amp;#34; style=&amp;#34;width: 300px;margin: 20px auto; display: block&amp;#34; @click=&amp;#34;handleUpload&amp;#34;&amp;gt;上传授权文件&amp;lt;/el-button&amp;gt;

		&amp;lt;el-descriptions title=&amp;#34;授权文件信息&amp;#34; :column=&amp;#34;1&amp;#34; border class=&amp;#34;margin-top&amp;#34;&amp;gt;
			&amp;lt;el-descriptions-item
				label=&amp;#34;开始时间&amp;#34;
				label-align=&amp;#34;right&amp;#34;
				align=&amp;#34;center&amp;#34;
			&amp;gt;
				&amp;lt;el-tag size=&amp;#34;small&amp;#34;&amp;gt;{{ LicenseInfo.startTime }} &amp;lt;/el-tag&amp;gt;
			&amp;lt;/el-descriptions-item&amp;gt;
			&amp;lt;el-descriptions-item label=&amp;#34;结束时间&amp;#34; label-align=&amp;#34;right&amp;#34; align=&amp;#34;center&amp;#34;&amp;gt;
				&amp;lt;el-tag size=&amp;#34;small&amp;#34;&amp;gt;{{ LicenseInfo.endTime }} &amp;lt;/el-tag&amp;gt;
			&amp;lt;/el-descriptions-item&amp;gt;
			&amp;lt;el-descriptions-item label=&amp;#34;用户数量&amp;#34; label-align=&amp;#34;right&amp;#34; align=&amp;#34;center&amp;#34;&amp;gt;
				&amp;lt;el-tag size=&amp;#34;small&amp;#34;&amp;gt;{{ LicenseInfo.userNum }} &amp;lt;/el-tag&amp;gt;
			&amp;lt;/el-descriptions-item&amp;gt;
			&amp;lt;el-descriptions-item label=&amp;#34;备注&amp;#34; label-align=&amp;#34;right&amp;#34; align=&amp;#34;center&amp;#34;&amp;gt;
				&amp;lt;el-tag size=&amp;#34;small&amp;#34;&amp;gt;{{ LicenseInfo.remark }} &amp;lt;/el-tag&amp;gt;
			&amp;lt;/el-descriptions-item&amp;gt;
		&amp;lt;/el-descriptions&amp;gt;

	&amp;lt;/div&amp;gt;

&amp;lt;/template&amp;gt;

&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;

import { UploadFilled } from &amp;#39;@element-plus/icons-vue&amp;#39;
import { uploadLicense, multipartUploadLicense } from &amp;#39;@/api/file&amp;#39;
import { LicenseControllerService } from &amp;#34;@/generated&amp;#34;
import type { UploadProps, UploadRawFile, UploadUserFile, UploadInstance } from &amp;#34;element-plus&amp;#34;;


let uploadRef=ref&amp;lt;UploadInstance&amp;gt;()
const fileList = ref&amp;lt;UploadUserFile[]&amp;gt;([])
const LicenseInfo = ref({
	startTime: &amp;#39;&amp;#39;,
	endTime: &amp;#39;&amp;#39;,
	userNum: &amp;#39;&amp;#39;,
	remark: &amp;#39;&amp;#39;,
})

// 上传状态和进度
const uploading = ref(false);
const uploadProgress = ref(0);

const handleExceed: UploadProps[&amp;#39;onExceed&amp;#39;] = (files) =&amp;gt; {
	ElMessageBox.alert(`当前限制选择 2 个文件，共选择了 ${files.length} 个文件,请重新选择`);
}

const beforeUpload: UploadProps[&amp;#39;beforeUpload&amp;#39;] = (rawFile: UploadRawFile) =&amp;gt; {
 if (rawFile.size / 1024 / 1024 &amp;gt; 2) {
		ElMessage.error(&amp;#39;文件大小不能超过2MB&amp;#39;)
		return false
	}

	const allowedExtensions = [&amp;#39;.lic&amp;#39;, &amp;#39;.keystore&amp;#39;]; // 允许的文件类型
	const fileExtension = rawFile.name.split(&amp;#39;.&amp;#39;).pop()?.toLowerCase();
	if (!fileExtension || !allowedExtensions.includes(`.${fileExtension}`)) {
		ElMessage.error(&amp;#39;不支持的文件类型&amp;#39;);
		return false;
	}

	return true
}

const handleChange: UploadProps[&amp;#39;onChange&amp;#39;] = (uploadFile, uploadFiles) =&amp;gt; {
	// 将上传的文件添加到 fileList 中
	fileList.value = uploadFiles.map(file =&amp;gt; file as UploadUserFile);
};

function handleUpload() {
	// 提取所有文件的 raw 属性
	const files = fileList.value.map(file =&amp;gt; file.raw as File);
	if(files.length === 0){
		ElMessage.error(&amp;#39;请选择要上传的授权文件&amp;#39;)
		return
	}
	// 上传文件
	multipartUploadLicense(files, (event: ProgressEvent) =&amp;gt; {
		uploading.value = true; // 显示进度条
		uploadProgress.value = Math.round(event.loaded / event.total * 100); // 更新进度
		//防止进度条的进度和上传的对勾显示时机不一致
 if(uploadProgress.value &amp;gt; 98){
			uploadProgress.value = 99
		}
	}).then(() =&amp;gt; {
		ElMessage({
			type: &amp;#39;success&amp;#39;,
			message: &amp;#39;上传成功&amp;#39;,
			grouping: true,
		})

		uploadRef.value!.clearFiles()
		uploadProgress.value = 100;
		uploading.value = false; // 隐藏进度条
		uploadProgress.value = 0; // 重置进度
		loadLicense()

	})
}

function loadLicense(){
	LicenseControllerService.verifyLicense().then(res =&amp;gt; {
		if(res.data &amp;amp;&amp;amp; res.code === 0){
			LicenseInfo.value = res.data as any
		}
	})
}

onMounted(() =&amp;gt; {
	loadLicense()
})

&amp;lt;/script&amp;gt;


&amp;lt;style scoped&amp;gt;

.margin-top {
	width: 80%;
	margin: 50px auto;
}
&amp;lt;/style&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>rar for linux使用报错</title><link>https://xiaoying.org.cn/pages/0a568c/</link><pubDate>Sat, 16 Sep 2023 21:53:42 +0000</pubDate><guid>https://xiaoying.org.cn/pages/0a568c/</guid><description>&lt;h2 id="rar-lib64libstdcso6-version-glibcxx_3421-not-found-required-by-rar"&gt;问题：rar: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21&amp;rsquo; not found (required by rar) &lt;a href="#rar-lib64libstdcso6-version-glibcxx_3421-not-found-required-by-rar" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202309162154851.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202309162154851.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202309162154851.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202309162154851.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202309162154851.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202309162154851.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="heading"&gt;问题原因（缺乏动态库文件） &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;/lib64/libstdc++.so.6: version `GLIBCXX_3.4.21&amp;rsquo;下没有GLIBCXX_3.4.21这个版本，简而言之就是/lib64/libstdc++.so.6下的glibc版本太低了。&lt;/p&gt;
&lt;h2 id="glibc3421"&gt;查看动态库中有哪些版本的glibc（发现缺少3.4.21的这个版本） &lt;a href="#glibc3421" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="db584de" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;strings /usr/lib64/libstdc&amp;#43;&amp;#43;.so.6 | grep GLIBC&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202309162154457.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202309162154457.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202309162154457.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202309162154457.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202309162154457.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202309162154457.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;
&lt;h2 id="heading-1"&gt;解决方法 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;由于anaconda中已经有了新版本glibc，所以复制anaconda中的glibc到/usr/lib64/中&lt;/p&gt;
&lt;h2 id="annacondaglibc"&gt;查找annaconda的glibc所在位置 &lt;a href="#annacondaglibc" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e607cfe" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;find / -name &amp;#34;libstdc&amp;#43;&amp;#43;.so*&amp;#34;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/202309162154802.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/202309162154802.png?w=480 480w,
 https://img.xiaoying.org.cn/img/202309162154802.png?w=768 768w,
 https://img.xiaoying.org.cn/img/202309162154802.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/202309162154802.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/202309162154802.png?w=2400 2400w
 " sizes="100vw" alt="img" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>tsconfig.json详解与常用配置</title><link>https://xiaoying.org.cn/pages/4dd9f3/</link><pubDate>Mon, 11 Mar 2024 15:56:29 +0000</pubDate><guid>https://xiaoying.org.cn/pages/4dd9f3/</guid><description>&lt;blockquote&gt;
 &lt;p&gt;&lt;strong&gt;参考文档&lt;/strong&gt;：&lt;a href="https://www.tslang.cn/docs/handbook/tsconfig-json.html" rel="external" target="_blank"&gt;tsconfig.json · TypeScript中文网 · TypeScript——JavaScript的超集 (tslang.cn)&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="heading"&gt;概述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果一个目录下存在一个&lt;code&gt;tsconfig.json&lt;/code&gt;文件，那么它意味着这个目录是TypeScript项目的根目录。 &lt;code&gt;tsconfig.json&lt;/code&gt;文件中指定了用来编译这个项目的根文件和编译选项。 &lt;code&gt;tsconfig.json&lt;/code&gt;文件可以是个空文件，那么所有默认的文件都会以默认配置选项编译。 在命令行上指定的编译选项会覆盖在&lt;code&gt;tsconfig.json&lt;/code&gt;文件里的相应选项 一个项目可以通过以下方式之一来编译：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;不带任何输入文件的情况下调用&lt;code&gt;tsc&lt;/code&gt;，编译器会从当前目录开始去查找&lt;code&gt;tsconfig.json&lt;/code&gt;文件，逐级向上搜索父目录。&lt;/li&gt;
&lt;li&gt;不带任何输入文件的情况下调用&lt;code&gt;tsc&lt;/code&gt;，且使用命令行参数&lt;code&gt;--project&lt;/code&gt;（或&lt;code&gt;-p&lt;/code&gt;）指定一个包含&lt;code&gt;tsconfig.json&lt;/code&gt;文件的目录。 当命令行上指定了输入文件时，&lt;code&gt;tsconfig.json&lt;/code&gt;文件会被忽略。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-1"&gt;顶层配置 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="50db5c5" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;{
 &amp;#34;extends&amp;#34;: &amp;#34;&amp;#34;,
 &amp;#34;compileOnSave&amp;#34;: true,
 &amp;#34;compilerOptions&amp;#34;: {},
 &amp;#34;files&amp;#34;: [],
 &amp;#34;include&amp;#34;: [],
 &amp;#34;exclude&amp;#34;: [],
 &amp;#34;references&amp;#34;: []
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;配置项&lt;/th&gt;
 &lt;th&gt;说明&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;extends&lt;/td&gt;
 &lt;td&gt;继承配置&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;compileOnSave&lt;/td&gt;
 &lt;td&gt;让IDE在保存文件的时候根据&lt;code&gt;tsconfig.json&lt;/code&gt;重新生成文件 要想支持这个特性需要Visual Studio 2015， TypeScript1.8.4以上并且安装&lt;a href="https://github.com/TypeStrong/atom-typescript" rel="external" target="_blank"&gt;atom-typescript&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;插件。&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;compilerOptions&lt;/td&gt;
 &lt;td&gt;编译选项，详见&lt;a href="https://xiaoying.org.cn/pages/4dd9f3/#compileroptions-编译选项"&gt;compilerOptions&lt;/a&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;files&lt;/td&gt;
 &lt;td&gt;指定一个包含相对或绝对文件路径的列表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;include&lt;/td&gt;
 &lt;td&gt;指定一个文件glob匹配模式列表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;exclude&lt;/td&gt;
 &lt;td&gt;指定一个文件glob匹配模式列表&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;references&lt;/td&gt;
 &lt;td&gt;一个对象的数组，指明要引用的工程。 每个引用的&lt;code&gt;path&lt;/code&gt;属性都可以指向到包含&lt;code&gt;tsconfig.json&lt;/code&gt;文件的目录，或者直接指向到配置文件本身（名字是任意的）&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="compileroptions-"&gt;compilerOptions 编译选项 &lt;a href="#compileroptions-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="aa7d7bc" class="language-json wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;{
 &amp;#34;extends&amp;#34;: &amp;#34;&amp;#34;,
 &amp;#34;compileOnSave&amp;#34;: false,
 &amp;#34;compilerOptions&amp;#34;: { //编译选项
 &amp;#34;allowJS&amp;#34;: false, // 允许编译器编译JS，JSX文件
 &amp;#34;checkJs&amp;#34;: false, // 	在 .js文件中报告错误。与allowJs配合使用。
 &amp;#34;allowSyntheticDefaultImports&amp;#34;: false, //允许从没有设置默认导出的模块中默认导入。这并不影响代码的输出，仅为了类型检查。默认值：module === &amp;#34;system&amp;#34; 或设置了 --esModuleInterop 且 module 不为 es2015 / esnext
 &amp;#34;allowUnreachableCode&amp;#34;: false, //不报告执行不到的代码错误。
 &amp;#34;allowUnusedLabels&amp;#34;: false, //不报告未使用的标签错误
 &amp;#34;alwaysStrict&amp;#34;: false, // 在代码中注入&amp;#39;use strict&amp;#39;,以严格模式解析并为每个源文件生成 &amp;#34;use strict&amp;#34;语句
 &amp;#34;charset&amp;#34;: &amp;#34;utf8&amp;#34;, //输入文件的字符集
 &amp;#34;declaration&amp;#34;: false, // 生成声明文件.d.ts，开启后会自动生成声明文件
 &amp;#34;declarationDir&amp;#34;: &amp;#34;&amp;#34;, // 指定生成声明文件存放目录
 &amp;#34;diagnostics&amp;#34;: false, // 显示诊断信息
 &amp;#34;extendedDiagnostics&amp;#34;: false, //显示详细的诊段信息
 &amp;#34;experimentalDecorators&amp;#34;:false,//启用实验性的ES装饰器
 &amp;#34;disableSizeLimit&amp;#34;: false, //禁用JavaScript工程体积大小的限制
 &amp;#34;emitBOM&amp;#34;: false, //在输出文件的开头加入BOM头（UTF-8 Byte Order Mark）。
 &amp;#34;forceConsistentCasingInFileNames&amp;#34;: false, //禁止对同一个文件的不一致的引用
 &amp;#34;incremental&amp;#34;: true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件，第二次编译会在第一次的基础上进行增量编译，可以提高编译的速度
 &amp;#34;isolatedModules&amp;#34;:false,//将每个文件作为单独的模块（与“ts.transpileModule”类似）。
 &amp;#34;listEmittedFiles&amp;#34;: false, //打印出编译后生成文件的名字
 &amp;#34;listFiles&amp;#34;: false, // 编译过程中打印文件名
 &amp;#34;tsBuildInfoFile&amp;#34;: &amp;#34;./buildFile&amp;#34;, // 增量编译文件的存储位置
 &amp;#34;target&amp;#34;: &amp;#34;ES5&amp;#34;, // 指定ECMAScript目标版本 &amp;#34;ES3&amp;#34;（默认）， &amp;#34;ES5&amp;#34;， &amp;#34;ES6&amp;#34;/ &amp;#34;ES2015&amp;#34;， &amp;#34;ES2016&amp;#34;， &amp;#34;ES2017&amp;#34;或 &amp;#34;ESNext&amp;#34;
 &amp;#34;module&amp;#34;: &amp;#34;CommonJS&amp;#34;, // 设置程序的模块系统， &amp;#34;None&amp;#34;， &amp;#34;CommonJS&amp;#34;， &amp;#34;AMD&amp;#34;， &amp;#34;System&amp;#34;， &amp;#34;UMD&amp;#34;， &amp;#34;ES6&amp;#34;或 &amp;#34;ES2015&amp;#34;, &amp;#34;ESNext&amp;#34;, &amp;#34;ES2020&amp;#34;，只有 &amp;#34;AMD&amp;#34;和 &amp;#34;System&amp;#34;能和 --outFile一起使用，&amp;#34;ES6&amp;#34;和 &amp;#34;ES2015&amp;#34;可使用在目标输出为 &amp;#34;ES5&amp;#34;或更低的情况下。默认值：target === &amp;#34;ES6&amp;#34; ? &amp;#34;ES6&amp;#34; : &amp;#34;commonjs&amp;#34;
 &amp;#34;moduleResolution&amp;#34;: &amp;#34;node&amp;#34;, // 模块解析策略，ts默认用node的解析策略，即相对的方式导入
 &amp;#34;jsx&amp;#34;:&amp;#34;Preserve&amp;#34;,//在 `.tsx`文件里支持JSX： `&amp;#34;React&amp;#34;`或 `&amp;#34;Preserve&amp;#34;`
 &amp;#34;jsxFactory&amp;#34;:&amp;#34;React.createElement&amp;#34;,//指定生成目标为react JSX时，使用的JSX工厂函数，比如 `React.createElement`或 `h`
 &amp;#34;newLine&amp;#34;: &amp;#34;crlf&amp;#34;, //当生成文件时指定行结束符： &amp;#34;crlf&amp;#34;（windows）或 &amp;#34;lf&amp;#34;（unix）。
 &amp;#34;noEmit&amp;#34;: false, // 不输出文件,即编译后不会生成任何js文件
 &amp;#34;noEmitOnError&amp;#34;: false, // 发送错误时不输出任何文件
 &amp;#34;noErrorTruncation&amp;#34;: false, //不截短错误消息
 &amp;#34;noFallthroughCasesInSwitch&amp;#34;: false, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
 &amp;#34;noImplicitAny&amp;#34;: false, // 不允许隐式的any类型,在表达式和声明上有隐含的 any类型时报错
 &amp;#34;noImplicitReturns&amp;#34;: false, //每个分支都会有返回值，不是函数的所有返回路径都有返回值时报错
 &amp;#34;noImplicitThis&amp;#34;: false, // 不允许this有隐式的any类型
 &amp;#34;noImplicitUseStrict&amp;#34;: false, //模块输出中不包含 &amp;#34;use strict&amp;#34;指令
 &amp;#34;noLib&amp;#34;: false, //不包含默认的库文件（ lib.d.ts）
 &amp;#34;noResolve&amp;#34;: false, //不把 /// &amp;lt;reference``&amp;gt;或模块导入的文件加到编译文件列表。
 &amp;#34;noEmitHelpers&amp;#34;: true, // 不生成helper函数，减小体积，需要额外安装，常配合importHelpers一起使用
 &amp;#34;noStrictGenericChecks&amp;#34;: false, //禁用在函数类型里对泛型签名进行严格检查
 &amp;#34;noUnusedLocals&amp;#34;: false, // 若有未使用的局部变量则抛错
 &amp;#34;noUnusedParameters&amp;#34;: false, // 检若有未使用的函数参数则抛错
 &amp;#34;lib&amp;#34;: [ //TS需要引用的库，即声明文件，es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性，通常都需要配置，如es8的数组新特性需要引入&amp;#34;ES2019.Array&amp;#34;,
 &amp;#34;DOM&amp;#34;,
 &amp;#34;ES2015&amp;#34;,
 &amp;#34;ScriptHost&amp;#34;,
 &amp;#34;ES2019.Array&amp;#34;
 ],
 &amp;#34;outDir&amp;#34;: &amp;#34;./dist&amp;#34;, // 指定输出目录
 &amp;#34;outFile&amp;#34;: &amp;#34;./app.js&amp;#34;, // 将多个相互依赖的文件生成一个文件，可以用在AMD模块中，即开启时应设置&amp;#34;module&amp;#34;: &amp;#34;AMD&amp;#34;,
 &amp;#34;preserveSymlinks&amp;#34;: false, //不把符号链接解析为其真实路径；将符号链接文件视为真正的文件
 &amp;#34;preserveWatchOutput&amp;#34;: false, //保留watch模式下过时的控制台输出
 &amp;#34;removeComments&amp;#34;: true, // 删除所有注释，除了以 /!*开头的版权信息
 &amp;#34;rootDir&amp;#34;: &amp;#34;./&amp;#34;, // 指定输出文件目录(用于输出)，用于控制输出目录结构
 &amp;#34;resolveJsonModule&amp;#34;:true,//允许导入扩展名为“.json”的模块
 &amp;#34;emitDeclarationOnly&amp;#34;: true, // 只生成声明文件，而不会生成js文件
 &amp;#34;sourceMap&amp;#34;: true, // 生成目标文件的sourceMap文件
 &amp;#34;inlineSourceMap&amp;#34;: false, // 生成目标文件的inline SourceMap，inline SourceMap会包含在生成的js文件中
 &amp;#34;inlineSources&amp;#34;: false, // 将代码与sourcemaps生成到一个文件中，要求同时设置了 --inlineSourceMap或 --sourceMap属性
 &amp;#34;declarationMap&amp;#34;: true, // 为声明文件生成sourceMap
 &amp;#34;types&amp;#34;: [], // 要包含的类型声明文件名列表
 &amp;#34;typeRoots&amp;#34;: [], // 声明文件目录，默认时node_modules/@types
 &amp;#34;importHelpers&amp;#34;: true, // 通过tslib引入helper函数，文件必须是模块（比如 __extends， __rest等）
 &amp;#34;downlevelIteration&amp;#34;: true, // 降级遍历器实现，如果目标源是es3/5，那么遍历器会有降级的实现
 &amp;#34;strict&amp;#34;: true, // 启用所有严格类型检查选项。启用 --strict相当于启用 --noImplicitAny, --noImplicitThis, --alwaysStrict， --strictNullChecks和 --strictFunctionTypes和--strictPropertyInitialization
 &amp;#34;skipLibCheck&amp;#34;: false, //忽略所有的声明文件（ *.d.ts）的类型检查
 &amp;#34;strictNullChecks&amp;#34;: true, // 不允许把null、undefined赋值给其他类型的变量.在严格的 null检查模式下， null和 undefined值不包含在任何类型里，只允许用它们自己和 any来赋值（有个例外， undefined可以赋值到 void）
 &amp;#34;strictFunctionTypes&amp;#34;: true, // 不允许函数参数双向协变
 &amp;#34;strictPropertyInitialization&amp;#34;: true, // 	确保类的非undefined属性已经在构造函数里初始化。若要令此选项生效，需要同时启用--strictNullChecks
 &amp;#34;suppressExcessPropertyErrors&amp;#34;: false, //阻止对对象字面量的额外属性检查
 &amp;#34;suppressImplicitAnyIndexErrors&amp;#34;: false, //阻止 --noImplicitAny对缺少索引签名的索引对象报错
 &amp;#34;strictBindCallApply&amp;#34;: true, // 严格的bind/call/apply检查
 &amp;#34;useDefineForClassFields&amp;#34;: true, //详见 https://jkchao.github.io/typescript-book-chinese/new/typescript-3.7.html#usedefineforclassfields-%E6%A0%87%E8%AE%B0%E4%B8%8E-declare-%E5%B1%9E%E6%80%A7%E4%BF%AE%E9%A5%B0%E7%AC%A6
 &amp;#34;esModuleInterop&amp;#34;: true, // 允许module.exports=xxx 导出，由import from 导入.因为很多老的js库使用了commonjs的导出方式，并且没有导出default属性
 &amp;#34;allowUmdGlobalAccess&amp;#34;: true, // 允许在模块中全局变量的方式访问umd模块
 &amp;#34;baseUrl&amp;#34;: &amp;#34;./&amp;#34;, // 解析非相对模块的基地址，默认是当前目录
 &amp;#34;paths&amp;#34;: { // 模块名到基于 baseUrl的路径映射的列表
 // 如使用jq时不想使用默认版本，而需要手动指定版本，可进行如下配置
 &amp;#34;jquery&amp;#34;: [
 &amp;#34;node_modules/jquery/dist/jquery.min.js&amp;#34;
 ]
 },
 &amp;#34;rootDirs&amp;#34;: [
 &amp;#34;src&amp;#34;,
 &amp;#34;out&amp;#34;
 ], // 将多个目录放在一个虚拟目录下，用于运行时，即编译后引入文件的位置可能发生变化，这也设置可以虚拟src和out在同一个目录下，不用再去改变路径也不会报错
 },
 &amp;#34;files&amp;#34;: [],
 &amp;#34;include&amp;#34;: [],
 &amp;#34;exclude&amp;#34;: [],
 &amp;#34;references&amp;#34;: []
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="files-include-exclude-"&gt;files include exclude 文件包含 &lt;a href="#files-include-exclude-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;quot;files&amp;quot;&lt;/code&gt;指定一个包含相对或绝对文件路径的列表。 &lt;code&gt;&amp;quot;include&amp;quot;&lt;/code&gt;和&lt;code&gt;&amp;quot;exclude&amp;quot;&lt;/code&gt;属性指定一个文件glob匹配模式列表。 支持的glob通配符有：&lt;/p&gt;</description></item><item><title>初始化客户端</title><link>https://xiaoying.org.cn/pages/87268f/</link><pubDate>Wed, 04 Oct 2023 14:33:24 +0000</pubDate><guid>https://xiaoying.org.cn/pages/87268f/</guid><description>&lt;h2 id="-sdk"&gt;&lt;a href="https://cloud.tencent.com/document/product/436/10199" rel="external" target="_blank"&gt;安装 SDK&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; &lt;a href="#-sdk" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;maven 安装 在 maven 工程的 pom.xml 文件中添加相关依赖，内容如下：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8e1cf08" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;dependency&amp;gt;
 &amp;lt;groupId&amp;gt;com.qcloud&amp;lt;/groupId&amp;gt;
 &amp;lt;artifactId&amp;gt;cos_api&amp;lt;/artifactId&amp;gt;
 &amp;lt;version&amp;gt;5.6.169&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;::: info 注意&lt;/p&gt;
&lt;p&gt;依赖坐标可能并非最新版本，请 &lt;a href="https://mvnrepository.com/artifact/com.qcloud/cos_api" rel="external" target="_blank"&gt;单击此处&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 获取最新版本。&lt;/p&gt;</description></item><item><title>文件上传</title><link>https://xiaoying.org.cn/pages/5f04a5/</link><pubDate>Tue, 03 Oct 2023 22:58:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/5f04a5/</guid><description>&lt;h2 id="heading"&gt;后端 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="cosmanagerjava"&gt;CosManager.java &lt;a href="#cosmanagerjava" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="28d9bda" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;	/**
	 * 上传对象
	 *
	 * @param key 唯一键
	 * @param file 文件
	 */
	public void putObject(String key, File file) {
		// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
		COSClient cosClient = createCOSClient();

		PutObjectRequest putObjectRequest = new PutObjectRequest(cosClientConfig.getBucket(), key,
				file);
		cosClient.putObject(putObjectRequest);

		// 确认本进程不再使用 cosClient 实例之后，关闭即可
		cosClient.shutdown();
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="coscontroller"&gt;CosController &lt;a href="#coscontroller" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="09083f8" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;import cn.hutool.core.io.FileUtil;
import com.hccake.ballcat.codegen.config.CosManager;
import com.hccake.ballcat.codegen.exception.BaseResponse;
import com.hccake.ballcat.codegen.exception.BusinessException;
import com.hccake.ballcat.codegen.exception.ErrorCode;
import com.hccake.ballcat.codegen.exception.ResultUtils;
import com.hccake.ballcat.codegen.model.entity.User;
import com.hccake.ballcat.codegen.model.enums.FileUploadBizEnum;
import com.hccake.ballcat.codegen.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.Arrays;
import java.util.Date;

/**
 * cos对象操作
 *
 */
@RestController
@RequestMapping(&amp;#34;/cos&amp;#34;)
@Slf4j
@Tag(name = &amp;#34;CosController&amp;#34;)
public class CosController {

	@Resource
	private UserService userService;

	@Resource
	private CosManager cosManager;


	/**文件上传
	 *
	 * @param multipartFile
	 * @param biz
	 * @param request
	 * @return
	 */
	@Operation(summary = &amp;#34;文件上传&amp;#34;)
	@Parameter(name=&amp;#34;biz&amp;#34;,description = &amp;#34;cos文件地址，可选user,file&amp;#34;,required = true)
	@PostMapping(&amp;#34;/upload&amp;#34;)
	public BaseResponse&amp;lt;String&amp;gt; upload(@RequestPart(&amp;#34;file&amp;#34;) MultipartFile multipartFile, String biz, HttpServletRequest request) {
		FileUploadBizEnum fileUploadBizEnum = FileUploadBizEnum.getEnumByValue(biz);
		if (fileUploadBizEnum == null) {
			throw new BusinessException(ErrorCode.PARAMS_ERROR);
		}
		validFile(multipartFile, fileUploadBizEnum);
		User loginUser = userService.getLoginUser(request);
		// 文件目录：根据业务、用户来划分
		Date now = new Date();
		long timestamp = now.getTime();
		String uuid = RandomStringUtils.randomAlphanumeric(8);
		String filename = uuid &amp;#43; &amp;#34;-&amp;#34; &amp;#43; timestamp;
		String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
		String filepath = String.format(&amp;#34;/%s/%s/%s.%s&amp;#34;, fileUploadBizEnum.getValue(), loginUser.getId(), filename, fileSuffix);
		File file = null;
		try {
			// 上传文件
			file = File.createTempFile(filepath, null);
			multipartFile.transferTo(file);
			cosManager.putObject(filepath, file);
			// 返回可访问地址
			String HOST = &amp;#34;https://img.xiaoying.org.cn&amp;#34;;
			return ResultUtils.success(HOST &amp;#43; filepath);
		} catch (Exception e) {
			log.error(&amp;#34;file upload error, filepath = &amp;#34; &amp;#43; filepath, e);
			throw new BusinessException(ErrorCode.SYSTEM_ERROR, &amp;#34;上传失败&amp;#34;);
		} finally {
			if (file != null) {
				// 删除临时文件
				boolean delete = file.delete();
				if (!delete) {
					log.error(&amp;#34;file delete error, filepath = {}&amp;#34;, filepath);
				}
			}
		}
	}

	/**
	 * 校验文件
	 *
	 * @param multipartFile
	 * @param fileUploadBizEnum 业务类型
	 */
	private void validFile(MultipartFile multipartFile, FileUploadBizEnum fileUploadBizEnum) {
		// 文件大小
		long fileSize = multipartFile.getSize();
		// 文件后缀
		String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
		final long ONE_M = 1024 * 1024L;
		final long ONE_F = 300 * 1024 * 1024L;
		if (FileUploadBizEnum.USER_AVATAR.equals(fileUploadBizEnum)) {
			if (!Arrays.asList(&amp;#34;jpeg&amp;#34;, &amp;#34;jpg&amp;#34;, &amp;#34;svg&amp;#34;, &amp;#34;png&amp;#34;, &amp;#34;webp&amp;#34;).contains(fileSuffix)) {
				throw new BusinessException(ErrorCode.PARAMS_ERROR, &amp;#34;图片类型错误,只能上传jpeg，jpg，svg，png，webp格式&amp;#34;);
			}
			if (fileSize &amp;gt; ONE_M) {
				throw new BusinessException(ErrorCode.PARAMS_ERROR, &amp;#34;图片大小不能超过 1M&amp;#34;);
			}
		}
		if (FileUploadBizEnum.FILE_UPLOAD.equals(fileUploadBizEnum)) {
			if (fileSize &amp;gt; ONE_F) {
				throw new BusinessException(ErrorCode.PARAMS_ERROR, &amp;#34;文件大小不能超过 300M&amp;#34;);
			}
 if (!Arrays.asList(&amp;#34;jpeg&amp;#34;, &amp;#34;jpg&amp;#34;, &amp;#34;svg&amp;#34;, &amp;#34;png&amp;#34;, &amp;#34;webp&amp;#34;).contains(fileSuffix)) {
 throw new BusinessException(ErrorCode.PARAMS_ERROR, &amp;#34;文件类型错误&amp;#34;);
 }
		}
	}
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;前端 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;基于vue3 + ts + elementplus&lt;/p&gt;</description></item><item><title>文件下载</title><link>https://xiaoying.org.cn/pages/03af39/</link><pubDate>Tue, 03 Oct 2023 22:58:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/03af39/</guid><description>&lt;h2 id="heading"&gt;获取到文件下载输入流 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;后端 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="cosmanagerjava"&gt;CosManager.java &lt;a href="#cosmanagerjava" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="883cd65" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; /**
 * 下载对象
 *
 * @param key 唯一键
 * @return 文件的字节数组
 */
 public byte[] getObject(String key)throws CosClientException, IOException {
 
 // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
 COSClient cosClient = createCOSClient();
 
 //下载文件
 GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);
 COSObjectInputStream cosObjectInput = null;

 try {
 COSObject cosObject = cosClient.getObject(getObjectRequest);
 cosObjectInput = cosObject.getObjectContent();
 } catch (CosServiceException e) {
 throw new BusinessException(ErrorCode.SYSTEM_ERROR, &amp;#34;下载失败&amp;#34;);
 }


 // 处理下载到的流
 // 这里是直接读取，按实际情况来处理
 byte[] bytes = null;
 try {
 bytes = IOUtils.toByteArray(cosObjectInput);

 } catch (IOException e) {
 throw new BusinessException(ErrorCode.SYSTEM_ERROR, &amp;#34;数据读取失败&amp;#34;);
 } finally {
 // 用完流之后一定要调用 close()
 cosObjectInput.close();
 }

 // 在流没有处理完之前，不能关闭 cosClient
 // 确认本进程不再使用 cosClient 实例之后，关闭即可
 cosClient.shutdown();
 return bytes;
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id="coscontrollerjava"&gt;CosController.java &lt;a href="#coscontrollerjava" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5f0c6de" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/**
 * 文件下载
 *
 * @param uploadFileRequest 文件对象
 * @param request 请求
 * @return 用户id
 */
 @Operation(summary = &amp;#34;文件下载&amp;#34;)
 @PostMapping(&amp;#34;/download&amp;#34;)
 public BaseResponse&amp;lt;byte[]&amp;gt; download(@RequestBody UploadFileRequest uploadFileRequest, HttpServletRequest request) {

 String filepath = uploadFileRequest.getFilepath();
 userService.getLoginUser(request);
 String key = filepath.replace(HOST, &amp;#34;&amp;#34;);
 String fileName = StringUtils.substringAfterLast(key, &amp;#34;/&amp;#34;);
 String fileExtension = StringUtils.substringAfter(fileName, &amp;#34;.&amp;#34;);

 try {

 boolean objectExists = cosClient.doesObjectExist(bucket, key);
 if (!objectExists) {
 // 如果对象不存在，返回相应的响应
 throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, &amp;#34;对象不存在&amp;#34;);
 }

 // 调用cosManager.download()下载文件
 byte[] data = cosManager.getObject(key);

 // 推断MIME类型
 MediaType mediaType;
 switch (fileExtension.toLowerCase()) {
 case &amp;#34;pdf&amp;#34;:
 mediaType = MediaType.APPLICATION_PDF;
 break;
 case &amp;#34;jpg&amp;#34;:
 mediaType = MediaType.IMAGE_JPEG;
 break;
 // 添加更多文件类型和对应的MediaType
 default:
 mediaType = MediaType.APPLICATION_OCTET_STREAM;
 break;
 }

 // 设置响应头
 HttpHeaders headers = new HttpHeaders();
 headers.setContentType(mediaType);
 headers.setContentDispositionFormData(&amp;#34;attachment&amp;#34;, fileName);

 return ResultUtils.success(data, fileName, mediaType.getType());

 } catch (Exception e) {
 log.error(&amp;#34;file download error, filepath = &amp;#34; &amp;#43; filepath, e);
 throw new BusinessException(ErrorCode.SYSTEM_ERROR, &amp;#34;下载失败:&amp;#34;&amp;#43; e.getMessage());
 }

 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;前端 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;

 &lt;blockquote&gt;
 &lt;p&gt;基于vue3 + ts + elementplus&lt;/p&gt;</description></item><item><title>文件删除</title><link>https://xiaoying.org.cn/pages/763456/</link><pubDate>Tue, 03 Oct 2023 22:58:38 +0000</pubDate><guid>https://xiaoying.org.cn/pages/763456/</guid><description>&lt;h2 id="heading"&gt;后端 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="cosmanagerjava"&gt;CosManager.java &lt;a href="#cosmanagerjava" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ed4e551" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; /**
 *删除对象
 *
 * @param key 唯一键
 */
 public void deleteObjects(String key) {
 // 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例，如果没有则创建
 COSClient cosClient = createCOSClient();
 
 //删除文件
 DeleteObjectRequest deleteObjectRequest = new DeleteObjectRequest(bucket,key);
 cosClient.deleteObject(deleteObjectRequest);
 
 // 确认本进程不再使用 cosClient 实例之后，关闭即可
 cosClient.shutdown();
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="coscontrollerjava"&gt;CosController.java &lt;a href="#coscontrollerjava" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="71b41b5" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt; /**
 * 文件删除
 *
 * @param uploadFileRequest 对象在cos中的url
 * @return 用户id
 */
 @Operation(summary = &amp;#34;文件删除&amp;#34;)
 @PostMapping(&amp;#34;/delete&amp;#34;)
 public BaseResponse deleteCos(@RequestBody UploadFileRequest uploadFileRequest, HttpServletRequest request) {
 userService.getLoginUser(request);
 String filepath = uploadFileRequest.getFilepath();
 String key = filepath.replace(HOST, &amp;#34;&amp;#34;);
 try {

 boolean objectExists = cosClient.doesObjectExist(cosClientConfig.getBucket(), key);
 if (!objectExists) {
 // 如果对象不存在，返回相应的响应
 throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, &amp;#34;对象不存在&amp;#34;);
 }
 // 尝试删除对象
 cosManager.deleteObjects(key);

 // 如果删除成功，返回成功响应
 return ResultUtils.success(key);

 } catch (Exception e) {
 // 捕获并处理异常
 log.error(&amp;#34;file delete error, key = {}&amp;#34;, key);

 // 返回包含错误信息的响应
 return ResultUtils.error(ErrorCode.SYSTEM_ERROR,&amp;#34;删除文件时发生异常: &amp;#34; &amp;#43; e.getMessage());
 }
 }&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;前端 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;

 &lt;blockquote&gt;
 &lt;p&gt;基于vue3 + ts + elementplus&lt;/p&gt;</description></item><item><title>NodeJs获取签名</title><link>https://xiaoying.org.cn/pages/abbecd/</link><pubDate>Sun, 14 Jan 2024 17:05:49 +0000</pubDate><guid>https://xiaoying.org.cn/pages/abbecd/</guid><description>&lt;p&gt;1、安装cos的nodejs依赖&lt;/p&gt;
&lt;p&gt;:::: el-tabs&lt;/p&gt;
&lt;p&gt;::: el-tab-pane label=yarn&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3be5cd2" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;yarn add cos-nodejs-sdk-v5 -D&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::: el-tab-pane label=npm&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4a54743" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;npm i cos-nodejs-sdk-v5 --save&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;:::
::::&lt;/p&gt;
&lt;p&gt;2、使用&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9a832e1" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;const COS = require(&amp;#39;cos-nodejs-sdk-v5&amp;#39;)

const cos = new COS({
 SecretId: config.secretId,
 SecretKey: config.secretKey,
 // 是否自定义域名
 Domain: config.customUrl ? config.customUrl : &amp;#39;&amp;#39;
 })

 const key = (config.path ? config.path : &amp;#39;&amp;#39;) &amp;#43; img.fileName

 // 去掉问号
 const queryStr = config.path?.startsWith(&amp;#39;?&amp;#39;) ? config.path.substring(1) : config.path
 const query = new Map(queryStr.split(&amp;#39;&amp;amp;&amp;#39;).map(value =&amp;gt; {
 const arr = value.split(&amp;#39;=&amp;#39;)
 return [arr[0], arr]
 }))

 let url = cos.getObjectUrl({
 Bucket: config.bucket,
 Region: config.area,
 Key: key,
 Sign: true,
 Query: query,
 Expires: expireSeconds
 }, (err, data) =&amp;gt; {
 if (err) {
 ctx.log.warn(err.message)
 }
 url = data.Url
 })
 return url&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;</description></item><item><title>pandoc使用</title><link>https://xiaoying.org.cn/pages/e3350e/</link><pubDate>Thu, 14 Sep 2023 21:48:35 +0000</pubDate><guid>https://xiaoying.org.cn/pages/e3350e/</guid><description>&lt;h2 id="heading"&gt;常规选项 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;指定输入格式 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="518eff0" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;-f FORMAT, -r FORMAT, --from=FORMAT, --read=FORMAT&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bibtex&lt;/code&gt;（&lt;a href="https://ctan.org/pkg/bibtex" rel="external" target="_blank"&gt;BibTeX&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;参考书目）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;biblatex&lt;/code&gt;（&lt;a href="https://ctan.org/pkg/biblatex" rel="external" target="_blank"&gt;BibLaTeX&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 参考书目）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commonmark&lt;/code&gt;（&lt;a href="https://commonmark.org/" rel="external" target="_blank"&gt;CommonMark&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; Markdown）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commonmark_x&lt;/code&gt;（带有扩展的&lt;a href="https://commonmark.org/" rel="external" target="_blank"&gt;CommonMark&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; Markdown）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;creole&lt;/code&gt;（&lt;a href="http://www.wikicreole.org/wiki/Creole1.0" rel="external" target="_blank"&gt;克里奥尔语 1.0&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csljson&lt;/code&gt;（&lt;a href="https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html" rel="external" target="_blank"&gt;CSL JSON&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;参考书目）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;csv&lt;/code&gt;（&lt;a href="https://tools.ietf.org/html/rfc4180" rel="external" target="_blank"&gt;CSV&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;表格）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tsv&lt;/code&gt;（&lt;a href="https://www.iana.org/assignments/media-types/text/tab-separated-values" rel="external" target="_blank"&gt;TSV&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 表）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docbook&lt;/code&gt;（&lt;a href="https://docbook.org/" rel="external" target="_blank"&gt;文档书&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;docx&lt;/code&gt;（&lt;a href="https://en.wikipedia.org/wiki/Office_Open_XML" rel="external" target="_blank"&gt;Word文档&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dokuwiki&lt;/code&gt;（&lt;a href="https://www.dokuwiki.org/dokuwiki" rel="external" target="_blank"&gt;DokuWiki 标记&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;endnotexml&lt;/code&gt;（&lt;a href="https://support.clarivate.com/Endnote/s/article/EndNote-XML-Document-Type-Definition" rel="external" target="_blank"&gt;EndNote XML 参考书目&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;epub&lt;/code&gt;（&lt;a href="http://idpf.org/epub" rel="external" target="_blank"&gt;EPUB&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fb2&lt;/code&gt;（&lt;a href="http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1" rel="external" target="_blank"&gt;FictionBook2&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 电子书）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gfm&lt;/code&gt;( &lt;a href="https://help.github.com/articles/github-flavored-markdown/" rel="external" target="_blank"&gt;GitHub 风格的 Markdown&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; )，或已弃用且不太准确的&lt;code&gt;markdown_github&lt;/code&gt;；&lt;a href="https://pandoc.org/MANUAL.html#markdown-variants" rel="external" target="_blank"&gt;&lt;code&gt;markdown_github&lt;/code&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;仅当您需要&lt;a href="https://pandoc.org/MANUAL.html#markdown-variants" rel="external" target="_blank"&gt;&lt;code&gt;gfm&lt;/code&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;haddock&lt;/code&gt;（&lt;a href="https://www.haskell.org/haddock/doc/html/ch03s08.html" rel="external" target="_blank"&gt;黑线鳕标记&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;html&lt;/code&gt;（&lt;a href="https://www.w3.org/html/" rel="external" target="_blank"&gt;HTML&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ipynb&lt;/code&gt;（&lt;a href="https://nbformat.readthedocs.io/en/latest/" rel="external" target="_blank"&gt;Jupyter 笔记本&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jats&lt;/code&gt;（&lt;a href="https://jats.nlm.nih.gov/" rel="external" target="_blank"&gt;JATS&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; XML）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jira&lt;/code&gt;（&lt;a href="https://jira.atlassian.com/secure/WikiRendererHelpAction.jspa?section=all" rel="external" target="_blank"&gt;Jira&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; /Confluence wiki 标记）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;json&lt;/code&gt;（原生 AST 的 JSON 版本）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;latex&lt;/code&gt;（&lt;a href="https://www.latex-project.org/" rel="external" target="_blank"&gt;乳胶&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdown&lt;/code&gt;( &lt;a href="https://pandoc.org/MANUAL.html#pandocs-markdown" rel="external" target="_blank"&gt;Pandoc 的 Markdown&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdown_mmd&lt;/code&gt;（&lt;a href="https://fletcherpenney.net/multimarkdown/" rel="external" target="_blank"&gt;多Markdown&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdown_phpextra&lt;/code&gt;( &lt;a href="https://michelf.ca/projects/php-markdown/extra/" rel="external" target="_blank"&gt;PHP Markdown 额外&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;markdown_strict&lt;/code&gt; （原始未扩展的&lt;a href="https://daringfireball.net/projects/markdown/" rel="external" target="_blank"&gt;Markdown&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mediawiki&lt;/code&gt;（&lt;a href="https://www.mediawiki.org/wiki/Help:Formatting" rel="external" target="_blank"&gt;MediaWiki 标记&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;man&lt;/code&gt;（&lt;a href="https://man.cx/groff_man(7)" rel="external" target="_blank"&gt;罗夫·曼&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;muse&lt;/code&gt;（&lt;a href="https://amusewiki.org/library/manual" rel="external" target="_blank"&gt;缪斯&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;native&lt;/code&gt;（哈斯克尔原生）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;odt&lt;/code&gt;（&lt;a href="https://en.wikipedia.org/wiki/OpenDocument" rel="external" target="_blank"&gt;ODT&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;opml&lt;/code&gt;（&lt;a href="http://dev.opml.org/spec2.html" rel="external" target="_blank"&gt;OPML&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;org&lt;/code&gt;（&lt;a href="https://orgmode.org/" rel="external" target="_blank"&gt;Emacs 组织模式&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ris&lt;/code&gt;（&lt;a href="https://en.wikipedia.org/wiki/RIS_(file_format)" rel="external" target="_blank"&gt;RIS&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 参考书目）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rtf&lt;/code&gt;（&lt;a href="https://en.wikipedia.org/wiki/Rich_Text_Format" rel="external" target="_blank"&gt;富文本格式&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rst&lt;/code&gt;（&lt;a href="https://docutils.sourceforge.io/docs/ref/rst/introduction.html" rel="external" target="_blank"&gt;重构文本&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;t2t&lt;/code&gt;（&lt;a href="https://txt2tags.org/" rel="external" target="_blank"&gt;txt2标签&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;textile&lt;/code&gt;（&lt;a href="https://textile-lang.com/" rel="external" target="_blank"&gt;纺织&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tikiwiki&lt;/code&gt;（&lt;a href="https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax" rel="external" target="_blank"&gt;TikiWiki 标记&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;twiki&lt;/code&gt;（&lt;a href="https://twiki.org/cgi-bin/view/TWiki/TextFormattingRules" rel="external" target="_blank"&gt;TWiki 标记&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;typst&lt;/code&gt;（&lt;a href="https://typst.app/" rel="external" target="_blank"&gt;打字员&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vimwiki&lt;/code&gt;（&lt;a href="https://vimwiki.github.io/" rel="external" target="_blank"&gt;维姆维基&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;）&lt;/li&gt;
&lt;li&gt;自定义Lua阅读器的路径，请参阅 下面的&lt;a href="https://pandoc.org/MANUAL.html#custom-readers-and-writers" rel="external" target="_blank"&gt;自定义阅读器和编写器&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;+EXTENSION&lt;/code&gt;可以通过将或附加&lt;code&gt;-EXTENSION&lt;/code&gt;到格式名称来单独启用或禁用扩展 。有关扩展及其名称的列表，请参阅下面的&lt;a href="https://pandoc.org/MANUAL.html#extensions" rel="external" target="_blank"&gt;扩展。&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;请参阅下面的&lt;a href="https://pandoc.org/MANUAL.html#option--list-input-formats" rel="external" target="_blank"&gt;&lt;code&gt;--list-input-formats&lt;/code&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;和&lt;a href="https://pandoc.org/MANUAL.html#option--list-extensions" rel="external" target="_blank"&gt;&lt;code&gt;--list-extensions&lt;/code&gt;&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;。&lt;/p&gt;</description></item><item><title>meilisearch部署</title><link>https://xiaoying.org.cn/pages/d09d47/</link><pubDate>Sun, 24 Sep 2023 22:03:03 +0000</pubDate><guid>https://xiaoying.org.cn/pages/d09d47/</guid><description>&lt;h2 id="heading"&gt;部署 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;官方对于部署的介绍非常详细，各种方案都提供了，我这里选择使用 docker 来进行部署。&lt;/p&gt;
&lt;p&gt;添加服务启动脚本&lt;code&gt;start.sh&lt;/code&gt;到&lt;code&gt;/tmp/scraper&lt;/code&gt;目录&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8c3505c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;docker run -itd --name meilisearch -p 7700:7700 --restart=always \
 -e MEILI_ENV=&amp;#34;production&amp;#34; -e MEILI_NO_ANALYTICS=true \
 -e MEILI_MASTER_KEY=&amp;#34;自定义一个不少于16字节的秘钥&amp;#34; \
 -v $(pwd)/meili_data:/meili_data \
 getmeili/meilisearch&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;自建的时候，需要将环境变量声明为生产，并且必须指定 master-key，否则将会提示无法使用。&lt;/p&gt;
&lt;p&gt;然后运行该脚本，服务启动，通过监听日志，查看服务状态是否正常。&lt;/p&gt;
&lt;p&gt;也可以请求服务的健康接口进行验证：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b173fed" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;$ curl -s http://localhost:7700/health | jq
{
 &amp;#34;status&amp;#34;: &amp;#34;available&amp;#34;
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;注意，生产模式下，只有这一个接口是不需要秘钥认证即可访问的，其他接口访问的时候都需要带上秘钥。&lt;/p&gt;
&lt;h2 id="key"&gt;创建搜索的key &lt;a href="#key" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上边有了一个 master-key 用于爬虫抓取使用，还需要创建一个只有搜索权限的 key，可通过如下命令进行创建&lt;code&gt;search.sh&lt;/code&gt;到&lt;code&gt;/tmp/scraper&lt;/code&gt;目录&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ac19168" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;curl \
 -X POST &amp;#39;http://localhost:7700/keys&amp;#39; \
 -H &amp;#39;Content-Type: application/json&amp;#39; \
 -H &amp;#39;Authorization: Bearer 你自定义的秘钥&amp;#39; \
 --data-binary &amp;#39;{
 &amp;#34;description&amp;#34;: &amp;#34;xiaoying.org.cn key&amp;#34;,
 &amp;#34;actions&amp;#34;: [&amp;#34;search&amp;#34;],
 &amp;#34;indexes&amp;#34;: [&amp;#34;blog&amp;#34;], // 第四步建立索引抓取配置中的index_uid的值需与该值保持一致
 &amp;#34;expiresAt&amp;#34;: &amp;#34;2099-01-01T00:00:00Z&amp;#34;
 }&amp;#39;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;创建完成之后，能看到返回内容中有一个 key 的字段，就是这个只有搜索权限的 key 了。&lt;/p&gt;</description></item><item><title>Partials使用指南</title><link>https://xiaoying.org.cn/pages/02e936/</link><pubDate>Thu, 18 Dec 2025 20:49:40 +0000</pubDate><guid>https://xiaoying.org.cn/pages/02e936/</guid><description>&lt;h2 id="-partials"&gt;什么是 Partials &lt;a href="#-partials" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Partials 是 Hugo 中的可重用模板片段，允许将模板的公共部分提取为独立文件，然后在其他模板中引用。这种模块化方式可以提高代码复用性，使模板结构更清晰，便于维护。&lt;/p&gt;
&lt;h2 id="heading"&gt;基本语法 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;基本引用方式 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c67ca7e" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 引用 partial --&amp;gt;
{{ partial &amp;#34;partial-name.html&amp;#34; . }}

&amp;lt;!-- 引用带路径的 partial --&amp;gt;
{{ partial &amp;#34;path/to/partial.html&amp;#34; . }}

&amp;lt;!-- 引用带缓存的 partial --&amp;gt;
{{ partialCached &amp;#34;partial-name.html&amp;#34; . }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;动态路径引用 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6827120" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 使用 printf 构建动态路径 --&amp;gt;
{{ partial (printf &amp;#34;%s/%s&amp;#34; ($.Scratch.Get &amp;#34;pathName&amp;#34;) &amp;#34;head/favicon.html&amp;#34;) . }}

&amp;lt;!-- 使用变量构建路径 --&amp;gt;
{{ $pathName := &amp;#34;docs&amp;#34; }}
{{ partial (printf &amp;#34;%s/%s&amp;#34; $pathName &amp;#34;sidebar.html&amp;#34;) . }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="-partials-"&gt;项目中的 Partials 使用示例 &lt;a href="#-partials-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-partial-"&gt;基础 Partial 引用 &lt;a href="#-partial-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="heading-3"&gt;静态路径引用 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="825bc39" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 引用 Google Fonts partial --&amp;gt;
{{- partialCached &amp;#34;google-fonts&amp;#34; . }}

&amp;lt;!-- 引用 favicon --&amp;gt;
{{ partialCached (printf &amp;#34;%s/%s&amp;#34; ($.Scratch.Get &amp;#34;pathName&amp;#34;) &amp;#34;head/favicon.html&amp;#34;) . }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id="heading-4"&gt;条件引用 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c086046" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 根据配置条件引用 --&amp;gt;
{{ if eq .Site.Params.docs.darkMode true -}}
 {{ $darkModeInit := resources.Get (printf &amp;#34;/%s/%s&amp;#34; ($.Scratch.Get &amp;#34;pathName&amp;#34;) &amp;#34;js/darkmode-init.js&amp;#34;) }}
{{ end -}}

&amp;lt;!-- 根据页面参数引用 --&amp;gt;
{{ if .Params.katex }}
 {{- partialCached (printf &amp;#34;%s/%s&amp;#34; ($.Scratch.Get &amp;#34;pathName&amp;#34;) &amp;#34;footer/katex.html&amp;#34;) . -}}
{{ end }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="-scratch-"&gt;使用 Scratch 存储和获取路径 &lt;a href="#-scratch-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;项目中大量使用 Scratch 来存储和获取路径名：&lt;/p&gt;</description></item><item><title>cloudreve部署</title><link>https://xiaoying.org.cn/pages/6a9d42/</link><pubDate>Wed, 03 Jan 2024 01:00:19 +0000</pubDate><guid>https://xiaoying.org.cn/pages/6a9d42/</guid><description>&lt;h2 id="heading"&gt;创建目录结构 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;请&lt;strong&gt;确保&lt;/strong&gt;运行之前：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;1、手动创建 &lt;code&gt;conf.ini&lt;/code&gt; 空文件或者符合 Cloudreve 配置文件规范的 &lt;code&gt;conf.ini&lt;/code&gt;, 并将 &lt;code&gt;/usr/local/cloudreve/conf.ini &lt;/code&gt;替换为该路径&lt;/p&gt;
&lt;p&gt;2 、手动创建 &lt;code&gt;cloudreve.db&lt;/code&gt; 空文件, 并将 &lt;code&gt;/usr/local/cloudreve/cloudreve.db &lt;/code&gt;替换为该路径&lt;/p&gt;
&lt;p&gt;3 、手动创建 &lt;code&gt;uploads&lt;/code&gt; 文件夹, 并将 &lt;code&gt;/usr/local/cloudreve/uploads&lt;/code&gt; 替换为该路径&lt;/p&gt;
&lt;p&gt;4、 手动创建 &lt;code&gt;avatar&lt;/code&gt; 文件夹，并将 &lt;code&gt;/usr/local/cloudreve/avatar&lt;/code&gt; 替换为该路径&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;或者，直接使用以下命令创建：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="da86771" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;cd /usr/local
&amp;amp;&amp;amp; mkdir -vp cloudreve/{uploads,avatar} \
&amp;amp;&amp;amp; touch cloudreve/conf.ini \
&amp;amp;&amp;amp; touch cloudreve/cloudreve.db&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;运行 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;然后，运行 docker container：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="fd1704d" class="language-shell wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;docker run -d \
-p 5212:5212 \
--mount type=bind,source=/usr/local/cloudreve/conf.ini,target=/cloudreve/conf.ini \
--mount type=bind,source=/usr/local/cloudreve/cloudreve.db,target=/cloudreve/cloudreve.db \
-v /usr/local/cloudreve/uploads:/cloudreve/uploads \
-v /usr/local/cloudreve/avatar:/cloudreve/avatar \
cloudreve/cloudreve:latest&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-2"&gt;添加域名 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这个根据自己的实际情况，我这里给 Nginx 添加配置文件，配置域名：&lt;/p&gt;</description></item><item><title>Hugo常用参数和变量指南</title><link>https://xiaoying.org.cn/pages/886ceb/</link><pubDate>Thu, 18 Dec 2025 21:26:40 +0000</pubDate><guid>https://xiaoying.org.cn/pages/886ceb/</guid><description>&lt;h2 id="heading"&gt;核心对象概述 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hugo模板系统提供了几个核心对象，用于访问网站的各种信息和配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.Site&lt;/code&gt; - 网站全局信息和配置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.Page&lt;/code&gt; - 当前页面的信息和属性&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.Params&lt;/code&gt; - 页面或网站的参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.File&lt;/code&gt; - 当前文件的信息&lt;/li&gt;
&lt;li&gt;&lt;code&gt;.Scratch&lt;/code&gt; - 临时数据存储&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="site-"&gt;&lt;code&gt;.Site&lt;/code&gt; 对象 &lt;a href="#site-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;基本属性 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="9a6ed42" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 网站基本信息 --&amp;gt;
{{ .Site.Title }} &amp;lt;!-- 网站标题 --&amp;gt;
{{ .Site.BaseURL }} &amp;lt;!-- 网站基础URL --&amp;gt;
{{ .Site.LanguageCode }} &amp;lt;!-- 网站语言代码 --&amp;gt;
{{ .Site.Language.Lang }} &amp;lt;!-- 当前语言 --&amp;gt;
{{ .Site.LanguagePrefix }} &amp;lt;!-- 语言前缀 --&amp;gt;
{{ .Site.Copyright }} &amp;lt;!-- 版权信息 --&amp;gt;
{{ .Site.LastChange }} &amp;lt;!-- 最后修改时间 --&amp;gt;
{{ .Site.BuildDrafts }} &amp;lt;!-- 是否构建草稿 --&amp;gt;
{{ .Site.IsMultiLingual }} &amp;lt;!-- 是否多语言网站 --&amp;gt;

&amp;lt;!-- 网站配置信息 --&amp;gt;
{{ .Site.Params }} &amp;lt;!-- 网站级参数 --&amp;gt;
{{ .Site.Menus }} &amp;lt;!-- 网站菜单 --&amp;gt;
{{ .Site.Taxonomies }} &amp;lt;!-- 分类法 --&amp;gt;
{{ .Site.Data }} &amp;lt;!-- 数据文件内容 --&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-2"&gt;常用方法 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ed4659e" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 获取页面 --&amp;gt;
{{ .Site.GetPage &amp;#34;section&amp;#34; &amp;#34;posts&amp;#34; }} &amp;lt;!-- 获取特定分区 --&amp;gt;
{{ .Site.GetPage &amp;#34;home&amp;#34; }} &amp;lt;!-- 获取首页 --&amp;gt;
{{ .Site.GetPage &amp;#34;/about/&amp;#34; }} &amp;lt;!-- 获取特定路径页面 --&amp;gt;

&amp;lt;!-- 获取资源 --&amp;gt;
{{ $resource := .Site.Resources.GetMatch &amp;#34;*.css&amp;#34; }} &amp;lt;!-- 匹配资源 --&amp;gt;
{{ $images := .Site.Resources.ByType &amp;#34;image&amp;#34; }} &amp;lt;!-- 按类型获取资源 --&amp;gt;

&amp;lt;!-- 获取菜单 --&amp;gt;
{{ $menu := .Site.Menus.main }} &amp;lt;!-- 获取主菜单 --&amp;gt;
{{ $menuItem := .Site.Menus.main 0 }} &amp;lt;!-- 获取菜单项 --&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-3"&gt;项目中的应用示例 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5ae04b5" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 获取网站配置的作者信息 --&amp;gt;
{{ $author := .Site.Params.author }}
{{ $authorName := $author.name }}
{{ $authorEmail := $author.email }}

&amp;lt;!-- 获取网站社交媒体链接 --&amp;gt;
{{ range $key, $value := .Site.Params.social }}
 &amp;lt;a href=&amp;#34;{{ $value }}&amp;#34; class=&amp;#34;social-link&amp;#34;&amp;gt;{{ $key }}&amp;lt;/a&amp;gt;
{{ end }}

&amp;lt;!-- 获取网站多语言信息 --&amp;gt;
{{ range .Site.Languages }}
 &amp;lt;a href=&amp;#34;{{ .Lang | relLangURL }}&amp;#34;&amp;gt;{{ .LanguageName }}&amp;lt;/a&amp;gt;
{{ end }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="page-"&gt;&lt;code&gt;.Page&lt;/code&gt; 对象 &lt;a href="#page-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-4"&gt;基本属性 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="36d9bc1" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 页面基本信息 --&amp;gt;
{{ .Page.Title }} &amp;lt;!-- 页面标题 --&amp;gt;
{{ .Page.Content }} &amp;lt;!-- 页面内容 --&amp;gt;
{{ .Page.Summary }} &amp;lt;!-- 页面摘要 --&amp;gt;
{{ .Page.Description }} &amp;lt;!-- 页面描述 --&amp;gt;
{{ .Page.Date }} &amp;lt;!-- 页面日期 --&amp;gt;
{{ .Page.Lastmod }} &amp;lt;!-- 最后修改时间 --&amp;gt;
{{ .Page.ExpiryDate }} &amp;lt;!-- 过期时间 --&amp;gt;
{{ .Page.PublishDate }} &amp;lt;!-- 发布日期 --&amp;gt;
{{ .Page.Weight }} &amp;lt;!-- 权重 --&amp;gt;
{{ .Page.Type }} &amp;lt;!-- 类型 --&amp;gt;
{{ .Page.Kind }} &amp;lt;!-- 种类 --&amp;gt;
{{ .Page.Section }} &amp;lt;!-- 分区 --&amp;gt;
{{ .Page.Slug }} &amp;lt;!-- URL别名 --&amp;gt;
{{ .Page.URL }} &amp;lt;!-- 页面URL --&amp;gt;
{{ .Page.RelPermalink }} &amp;lt;!-- 相对永久链接 --&amp;gt;
{{ .Page.RelRef }} &amp;lt;!-- 相对引用 --&amp;gt;

&amp;lt;!-- 页面状态 --&amp;gt;
{{ .Page.Draft }} &amp;lt;!-- 是否为草稿 --&amp;gt;
{{ .Page.IsHome }} &amp;lt;!-- 是否为首页 --&amp;gt;
{{ .Page.IsPage }} &amp;lt;!-- 是否为普通页面 --&amp;gt;
{{ .Page.IsSection }} &amp;lt;!-- 是否为分区页面 --&amp;gt;
{{ .Page.IsNode }} &amp;lt;!-- 是否为节点 --&amp;gt;
{{ .Page.IsMenu }} &amp;lt;!-- 是否在菜单中 --&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-5"&gt;内容相关属性 &lt;a href="#heading-5" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="57fa78b" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 字数统计 --&amp;gt;
{{ .Page.WordCount }} &amp;lt;!-- 字数 --&amp;gt;
{{ .Page.ReadingTime }} &amp;lt;!-- 预计阅读时间（分钟） --&amp;gt;
{{ .Page.FuzzyWordCount }} &amp;lt;!-- 模糊字数 --&amp;gt;
{{ .Page.Len }} &amp;lt;!-- 内容长度 --&amp;gt;

&amp;lt;!-- 目录和导航 --&amp;gt;
{{ .Page.TableOfContents }} &amp;lt;!-- 目录 --&amp;gt;
{{ .Page.Next }} &amp;lt;!-- 下一页 --&amp;gt;
{{ .Page.Prev }} &amp;lt;!-- 上一页 --&amp;gt;
{{ .Page.First }} &amp;lt;!-- 第一页 --&amp;gt;
{{ .Page.Last }} &amp;lt;!-- 最后一页 --&amp;gt;
{{ .Page.NextInSection }} &amp;lt;!-- 分区内下一页 --&amp;gt;
{{ .Page.PrevInSection }} &amp;lt;!-- 分区内上一页 --&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-6"&gt;页面参数 &lt;a href="#heading-6" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5f4b6be" class="language-go wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 获取页面参数 --&amp;gt;
{{ .Page.Params.author }} &amp;lt;!-- 页面作者 --&amp;gt;
{{ .Page.Params.tags }} &amp;lt;!-- 页面标签 --&amp;gt;
{{ .Page.Params.categories }} &amp;lt;!-- 页面分类 --&amp;gt;
{{ .Page.Params.featuredImage }} &amp;lt;!-- 特色图片 --&amp;gt;
{{ .Page.Params.showToc }} &amp;lt;!-- 是否显示目录 --&amp;gt;

&amp;lt;!-- 检查参数是否存在 --&amp;gt;
{{ if .Page.Params.showAuthor }}
 &amp;lt;div class=&amp;#34;author&amp;#34;&amp;gt;{{ .Page.Params.author }}&amp;lt;/div&amp;gt;
{{ end }}

&amp;lt;!-- 使用默认值 --&amp;gt;
{{ $author := .Page.Params.author | default .Site.Params.author }}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="params-"&gt;&lt;code&gt;.Params&lt;/code&gt; 对象 &lt;a href="#params-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-7"&gt;参数层级 &lt;a href="#heading-7" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hugo中的参数有层级结构，优先级从高到低：&lt;/p&gt;</description></item><item><title>Hugo Bootstrap使用指南</title><link>https://xiaoying.org.cn/pages/f9a4a3/</link><pubDate>Wed, 17 Dec 2025 16:00:00 +0000</pubDate><guid>https://xiaoying.org.cn/pages/f9a4a3/</guid><description>&lt;h2 id="bootstrap"&gt;Bootstrap集成方式 &lt;a href="#bootstrap" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading"&gt;模块导入配置 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;themes/lotusdocs/config.toml&lt;/code&gt;中配置Bootstrap模块导入：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="bdc006b" class="language-toml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;[module]
[[module.imports]]
path = &amp;#34;github.com/twbs/bootstrap&amp;#34;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading-1"&gt;资源管道处理 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;通过Hugo资源管道处理Bootstrap资源：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b22bc1d" class="language-html wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;&amp;lt;!-- 在layouts/partials/basic.html中 --&amp;gt;
{{ $bootstrapJS := resources.Get &amp;#34;js/bootstrap.js&amp;#34; }}
{{ $bootstrapJS = $bootstrapJS | js.Build (dict &amp;#34;targetPath&amp;#34; &amp;#34;js/bootstrap.bundle.min.js&amp;#34; &amp;#34;minify&amp;#34; true) }}
&amp;lt;script src=&amp;#34;{{ $bootstrapJS.RelPermalink }}&amp;#34; defer&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="scss"&gt;SCSS变量自定义 &lt;a href="#scss" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;assets/scss/_variables.scss&lt;/code&gt;中自定义Bootstrap变量：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5959c77" class="language-scss wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// Bootstrap变量覆盖
$primary: #2563eb;
$secondary: #64748b;
$success: #16a34a;
$info: #0ea5e9;
$warning: #f59e0b;
$danger: #dc2626;

// 导航栏自定义
$navbar-padding-y: 0.5rem;
$navbar-dark-color: rgba($white, .85);
$navbar-dark-hover-color: $white;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="bootstrap-1"&gt;Bootstrap组件初始化 &lt;a href="#bootstrap-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-2"&gt;核心组件导入 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在&lt;code&gt;assets/docs/js/bootstrap.js&lt;/code&gt;中导入和初始化Bootstrap组件：&lt;/p&gt;</description></item><item><title>DOM操作与全局JS注册指南</title><link>https://xiaoying.org.cn/pages/f625bb/</link><pubDate>Thu, 18 Dec 2025 20:56:26 +0000</pubDate><guid>https://xiaoying.org.cn/pages/f625bb/</guid><description>&lt;h2 id="dom"&gt;DOM操作 &lt;a href="#dom" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="dom-1"&gt;基本DOM选择器 &lt;a href="#dom-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;项目中常用的DOM选择器方法：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="4472c43" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 通过ID选择元素
const navbar = document.getElementById(&amp;#34;topnav&amp;#34;);
const mybutton = document.getElementById(&amp;#34;back-to-top&amp;#34;);

// 通过类名选择元素
const navbarToggler = document.querySelector(&amp;#39;.navbar-toggler&amp;#39;);
const navbarCollapse = document.querySelector(&amp;#39;.navbar-collapse&amp;#39;);
const tooltipTriggerList = document.querySelectorAll(&amp;#39;[data-bs-toggle=&amp;#34;tooltip&amp;#34;]&amp;#39;)

// 通过标签名选择元素
var elements = document.getElementById(&amp;#34;navigation&amp;#34;).getElementsByTagName(&amp;#34;a&amp;#34;);

// 使用更复杂的选择器
const targetElement = document.querySelector(targetId);
const dropdowns = document.querySelectorAll(&amp;#39;.dropdown&amp;#39;);&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="heading"&gt;事件监听器 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="domcontentloaded"&gt;DOMContentLoaded事件 &lt;a href="#domcontentloaded" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;DOMContentLoaded&lt;/code&gt;是项目中最常用的事件，确保DOM完全加载后再执行脚本：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2832818" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 基本用法
document.addEventListener(&amp;#39;DOMContentLoaded&amp;#39;, function() {
 // 在这里执行DOM操作
 renderMathInElement(document.getElementById(&amp;#34;content&amp;#34;), {
 // 配置选项
 });
});

// 箭头函数写法
document.addEventListener(&amp;#39;DOMContentLoaded&amp;#39;, () =&amp;gt; {
 window.ImageHandler.init();
});&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id="heading-1"&gt;其他常用事件监听 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="ad12da0" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 滚动事件
window.addEventListener(&amp;#39;scroll&amp;#39;, function() {
 const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
 // 处理滚动逻辑
});

// 点击事件
document.addEventListener(&amp;#39;click&amp;#39;, function(event) {
 var isClickInsideElement = suggestions.contains(event.target);
 if (!isClickInsideElement) {
 suggestions.classList.add(&amp;#39;d-none&amp;#39;);
 }
});

// 键盘事件
document.addEventListener(&amp;#39;keydown&amp;#39;, (e) =&amp;gt; {
 if (e.key === &amp;#39;Escape&amp;#39;) {
 this.closeZoom();
 }
});

// 窗口大小变化事件
window.addEventListener(&amp;#39;resize&amp;#39;, function() {
 if (window.innerWidth &amp;gt;= 992) {
 // 处理响应式逻辑
 }
});&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="dom-2"&gt;DOM操作实例 &lt;a href="#dom-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;h4 id="heading-2"&gt;元素样式操作 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3c2a809" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 添加/移除类
navbar.classList.add(&amp;#34;nav-sticky&amp;#34;);
navbar.classList.remove(&amp;#34;scrolled&amp;#34;);
navbar.classList.toggle(&amp;#39;open&amp;#39;);

// 直接修改样式
mybutton.style.display = &amp;#34;block&amp;#34;;
overlay.style.borderBottom = &amp;#39;1px solid var(--alert-border-color)&amp;#39;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id="heading-3"&gt;元素属性操作 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8a4de0c" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 获取属性
const isExpanded = navbarToggler.getAttribute(&amp;#39;aria-expanded&amp;#39;) === &amp;#39;true&amp;#39;;
const href = elem.target.getAttribute(&amp;#34;href&amp;#34;);

// 设置属性
navbarToggler.setAttribute(&amp;#39;aria-expanded&amp;#39;, &amp;#39;false&amp;#39;);
element.setAttribute(&amp;#39;data-collapse-state&amp;#39;, &amp;#39;collapsed&amp;#39;);&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h4 id="heading-4"&gt;创建和插入元素 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h4&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6189915" class="language-javascript wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;// 创建新元素
const overlay = document.createElement(&amp;#39;div&amp;#39;);
overlay.className = &amp;#39;image-overlay&amp;#39;;

const collapseBtn = document.createElement(&amp;#39;button&amp;#39;);
collapseBtn.setAttribute(&amp;#39;type&amp;#39;, &amp;#39;button&amp;#39;);

// 克隆元素
const clonedElement = this.cloneImageElement(element);

// 插入元素
document.body.appendChild(overlay);
parent.insertBefore(wrapper, block);
wrapper.appendChild(block);&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="js"&gt;全局JS注册 &lt;a href="#js" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="window"&gt;直接挂载到window对象 &lt;a href="#window" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;最简单直接的方式是将函数或对象挂载到window对象上：&lt;/p&gt;</description></item><item><title>zabbix部署</title><link>https://xiaoying.org.cn/pages/bd19b2/</link><pubDate>Tue, 20 Aug 2024 15:33:35 +0000</pubDate><guid>https://xiaoying.org.cn/pages/bd19b2/</guid><description>&lt;h2 id="docker-composeyaml"&gt;编写docker-compose.yaml文件 &lt;a href="#docker-composeyaml" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="00260ff" class="language-yaml wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;version: &amp;#39;3&amp;#39;
services:
 # DB
 mysql:
 image: mysql:8.0
 container_name: mysql
 volumes:
 - ${DEPLOY_PATH}/data:/var/lib/mysql
 - ${DEPLOY_PATH}/mysql/conf:/etc/mysql/conf.d
 - ${DEPLOY_PATH}/mysql/logs:/var/log/mysql
 - /etc/localtime:/etc/localtime:ro
 restart: always
 privileged: true
 environment:
 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
 - MYSQL_DATABASE=zabbix
 - MYSQL_USER=zabbix
 - MYSQL_PASSWORD=${MYSQL_PASSWORD}
 - TZ=Asia/Shanghai
 - LANG=en_US.UTF-8
 ports:
 - &amp;#34;3306:3306&amp;#34;

 # Gateway
 zabbix-gateway:
 image: zabbix/zabbix-java-gateway:6.0-centos-latest
 container_name: zabbix-gateway
 volumes:
 - /etc/localtime:/etc/localtime:ro
 restart: always
 privileged: true
 ports:
 - &amp;#34;10052:10052&amp;#34;

 # Server
 zabbix-server:
 image: zabbix/zabbix-server-mysql:6.0-centos-latest
 container_name: zabbix-server
 volumes:
 - /etc/localtime:/etc/localtime:ro
 - ${DEPLOY_PATH}/snmptraps:/var/lib/zabbix/snmptraps
 - ${DEPLOY_PATH}/mibs:/var/lib/zabbix/mibs
 - ${DEPLOY_PATH}/alertscripts:/usr/lib/zabbix/alertscripts
 - ${DEPLOY_PATH}/externalscripts:/usr/lib/zabbix/externalscripts
 restart: always
 privileged: true
 environment:
 - ZBX_LISTENPORT=10051
 - DB_SERVER_HOST=mysql
 - DB_SERVER_PORT=3306
 - MYSQL_DATABASE=zabbix
 - MYSQL_USER=root
 - MYSQL_PASSWORD=${MYSQL_PASSWORD}
 - MYSQL_ROOT_PASSWORD=zabbix
 - ZBX_CACHESIZE=256M
 - ZBX_HISTORYCACHESIZE=256M
 - ZBX_HISTORYINDEXCACHESIZE=16M
 - ZBX_TRENDCACHESIZE=128M
 - ZBX_VALUECACHESIZE=128M
 - ZBX_STARTPINGERS=64
 - ZBX_IPMIPOLLERS=1
 - ZBX_ENABLE_SNMP_TRAPS=true
 - ZBX_STARTTRAPPERS=1
 - ZBX_JAVAGATEWAY_ENABLE=true
 - ZBX_JAVAGATEWAY=zabbix-gateway
 - ZBX_STARTJAVAPOLLERS=1
 ports:
 - &amp;#34;10051:10051&amp;#34;
 links:
 - mysql
 - zabbix-gateway

 # WEB
 zabbix-web:
 image: zabbix/zabbix-web-nginx-mysql:6.0-centos-latest
 container_name: zabbix-web
 volumes:
 - ${DEPLOY_PATH}/font/simfang.ttf:/usr/share/zabbix/assets/fonts/DejaVuSans.ttf
 - /etc/localtime:/etc/localtime
 restart: always
 privileged: true
 environment:
 - ZBX_SERVER_NAME=Zabbix 6.0
 - ZBX_SERVER_HOST=zabbix-server
 - ZBX_SERVER_PORT=10051
 - DB_SERVER_HOST=mysql
 - DB_SERVER_PORT=3306
 - MYSQL_DATABASE=zabbix
 - MYSQL_USER=root
 - MYSQL_PASSWORD=${MYSQL_PASSWORD}
 - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
 - PHP_TZ=Asia/Shanghai
 ports:
 - &amp;#34;8081:8080&amp;#34;
 links:
 - mysql
 - zabbix-server
 

 zabbix-agent:
 image: zabbix/zabbix-agent
 container_name: zabbix-agent
 volumes:
 - /etc/localtime:/etc/localtime:ro
 - ${DEPLOY_PATH}/zabbix_agentd.d:/etc/zabbix/zabbix_agentd.d:ro
 - ${DEPLOY_PATH}/var/lib/zabbix/modules:/var/lib/zabbix/modules:ro
 - ${DEPLOY_PATH}/var/lib/zabbix/enc:/var/lib/zabbix/enc:ro
 - ${DEPLOY_PATH}/var/lib/zabbix/ssh_keys:/var/lib/zabbix/ssh_keys:ro
 tmpfs: /tmp
 restart: always
 privileged: true
 ports:
 - &amp;#34;10050:10050&amp;#34;
 pid: &amp;#34;host&amp;#34;
 stop_grace_period: 5s
 environment:
 - ZBX_SERVER_HOST=${Server}
 - ZBX_SERVER_PORT=10051
 - ZBX_HOSTNAME=${Server}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="env"&gt;编写.env文件 &lt;a href="#env" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="71e98ee" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;DEPLOY_PATH=&amp;#39;&amp;#39; //部署路径
MYSQL_ROOT_PASSWORD=&amp;#39;&amp;#39; //数据库密码
MYSQL_PASSWORD=&amp;#39;&amp;#39; //数据库管理员密码
Server=&amp;#39;&amp;#39; //服务器IP&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="sever-severactive-hostnameip"&gt;修改配置文件&lt;code&gt;Sever&lt;/code&gt;, &lt;code&gt;SeverActive&lt;/code&gt;, &lt;code&gt;Hostname&lt;/code&gt;为服务器IP &lt;a href="#sever-severactive-hostnameip" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b310fe3" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;vi /etc/zabbix_agentd.conf&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;::: note 提示&lt;/p&gt;</description></item><item><title>CSS高度自适应</title><link>https://xiaoying.org.cn/pages/038d39/</link><pubDate>Sat, 07 Mar 2026 15:12:58 +0000</pubDate><guid>https://xiaoying.org.cn/pages/038d39/</guid><description>&lt;h2 id="heading"&gt;核心属性搭配 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2d4fabf" class="language-css wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;/* 最优组合：按需渲染&amp;#43;预占位&amp;#43;布局下限&amp;#43;自适应高度 */
.container {
 content-visibility: auto; /* 浏览器按需渲染，未进视口不计算布局，优化性能 */
 contain-intrinsic-size: 400px; /* 仅配合auto生效，未进视口时的预渲染占位高度 */
 min-height: 400px; /* 全局布局下限，容器高度永远不低于该值，全程生效 */
 height: fit-content; /* 容器最终自适应内容高度，保留核心自适应逻辑 */
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="contain-intrinsic-size-vs-min-height-"&gt;contain-intrinsic-size vs min-height 核心区别 &lt;a href="#contain-intrinsic-size-vs-min-height-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th style="text-align: center"&gt;特性&lt;/th&gt;
 &lt;th style="text-align: center"&gt;contain-intrinsic-size&lt;/th&gt;
 &lt;th style="text-align: center"&gt;min-height&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;生效依赖&lt;/td&gt;
 &lt;td style="text-align: center"&gt;仅对&lt;code&gt;content-visibility: auto&lt;/code&gt;元素生效&lt;/td&gt;
 &lt;td style="text-align: center"&gt;无依赖，所有元素均可使用&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;作用阶段&lt;/td&gt;
 &lt;td style="text-align: center"&gt;仅元素&lt;strong&gt;未进入视口&lt;/strong&gt;时生效&lt;/td&gt;
 &lt;td style="text-align: center"&gt;元素布局&lt;strong&gt;全程生效&lt;/strong&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;生效逻辑&lt;/td&gt;
 &lt;td style="text-align: center"&gt;非约束性，仅为浏览器提供高度预估值&lt;/td&gt;
 &lt;td style="text-align: center"&gt;约束性，强制规定容器高度最小值&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;内容覆盖后表现&lt;/td&gt;
 &lt;td style="text-align: center"&gt;元素进视口后，被真实内容高度覆盖&lt;/td&gt;
 &lt;td style="text-align: center"&gt;内容高度超值时自适应，低值时保持定值&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td style="text-align: center"&gt;无 auto 时的表现&lt;/td&gt;
 &lt;td style="text-align: center"&gt;完全失效，对布局无任何影响&lt;/td&gt;
 &lt;td style="text-align: center"&gt;正常生效，独立布局属性&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="heading-1"&gt;关键使用原则 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;content-visibility: auto&lt;/code&gt;：长列表 / 动态内容 / 多卡片容器首选，核心优化首屏渲染性能，减少高度计算导致的闪烁&lt;/li&gt;
&lt;li&gt;&lt;code&gt;contain-intrinsic-size&lt;/code&gt;：auto 的&lt;strong&gt;专属配套属性&lt;/strong&gt;，解决未渲染元素的高度塌陷，值贴近容器实际平均高度即可&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min-height&lt;/code&gt;：布局稳定的&lt;strong&gt;基础保障&lt;/strong&gt;，与 auto 无依赖，单独使用也能防闪烁，和前两者搭配解决进视口后的布局抖动&lt;/li&gt;
&lt;li&gt;&lt;code&gt;height: fit-content&lt;/code&gt;：保留容器自适应核心逻辑，让高度最终由内容决定，不被固定值限制&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="--"&gt;适用 &amp;amp; 禁用场景 &lt;a href="#--" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="content-visibility-auto"&gt;适用（content-visibility: auto） &lt;a href="#content-visibility-auto" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;长列表：商品 / 文章 / 评论列表&lt;/li&gt;
&lt;li&gt;动态内容容器：异步加载的图文、接口渲染内容&lt;/li&gt;
&lt;li&gt;非首屏大模块：侧边栏二级内容、页脚、分页模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="content-visibility-auto-1"&gt;禁用（content-visibility: auto） &lt;a href="#content-visibility-auto-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;首屏核心内容：banner、头部导航、首屏卡片&lt;/li&gt;
&lt;li&gt;小尺寸容器：按钮、标签、小图标（无性能优化意义）&lt;/li&gt;
&lt;li&gt;需实时计算高度的嵌套容器：flex/grid 子元素自适应布局&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>配置algolia</title><link>https://xiaoying.org.cn/pages/20b6a7/</link><pubDate>Sun, 24 Aug 2025 20:40:01 +0000</pubDate><guid>https://xiaoying.org.cn/pages/20b6a7/</guid><description>&lt;h2 id="_1"&gt;_1、注册账号 &lt;a href="#_1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先需要去 &lt;a href="https://www.algolia.com/" rel="external" target="_blank"&gt;algolia&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 官网注册自己的账号，可以直接使用 Github 或者其他邮箱注册登录。&lt;/p&gt;
&lt;p&gt;新账号会自动创建一个&lt;em&gt;Application&lt;/em&gt; ，也可以自己创建一个新的&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20250824130816604.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20250824130816604.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20250824130816604.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20250824130816604.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20250824130816604.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20250824130816604.png?w=2400 2400w
 " sizes="100vw" alt="image-20250824130816421" loading="lazy"&gt;


&lt;/p&gt;
&lt;p&gt;










 &lt;img class="post-image zoomable" src="https://img.xiaoying.org.cn/img/20250824130142740.png?w=1600" srcset="
 https://img.xiaoying.org.cn/img/20250824130142740.png?w=480 480w,
 https://img.xiaoying.org.cn/img/20250824130142740.png?w=768 768w,
 https://img.xiaoying.org.cn/img/20250824130142740.png?w=1024 1024w,
 https://img.xiaoying.org.cn/img/20250824130142740.png?w=1600 1600w,
 https://img.xiaoying.org.cn/img/20250824130142740.png?w=2400 2400w
 " sizes="100vw" alt="image-20250824130142558" loading="lazy"&gt;


&lt;/p&gt;</description></item><item><title>安装 acme.sh</title><link>https://xiaoying.org.cn/pages/86faba/</link><pubDate>Thu, 29 Aug 2024 12:24:47 +0000</pubDate><guid>https://xiaoying.org.cn/pages/86faba/</guid><description>&lt;p&gt;ACME（自动证书管理环境）是一个互联网工程任务组维护的协议，它允许自动化 Web 服务器证书的部署，&lt;a href="https://github.com/acmesh-official/acme.sh" rel="external" target="_blank"&gt;acme.sh&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 是支持 ACME 协议流行的客户端之一，可以通过其实现 SSL 证书的自动申请、续期等。本文将为您介绍如何使用 acme.sh 自动申请证书。&lt;/p&gt;
&lt;!-- more --&gt;
&lt;h2 id="-acmesh"&gt;安装 acme.sh &lt;a href="#-acmesh" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading"&gt;全新安装 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;适用于未安装 acme.sh 的用户，使用以下命令安装 acme.sh 客户端：&lt;/p&gt;</description></item><item><title>一键部署脚本</title><link>https://xiaoying.org.cn/pages/c46d3c/</link><pubDate>Thu, 02 Oct 2025 15:22:25 +0000</pubDate><guid>https://xiaoying.org.cn/pages/c46d3c/</guid><description>&lt;p&gt;一键远程部署脚本，只需一行命令，即可开启您的Linux管理之旅&lt;/p&gt;
&lt;h2 id="_1ssl"&gt;_1、ssl &lt;a href="#_1ssl" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8a376a4" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;bash &amp;lt;(curl -fsSL https://cnb.xiaoying.org.cn/file/acme.sh)&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="_2docker"&gt;_2、docker &lt;a href="#_2docker" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cb21a6c" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;bash &amp;lt;(curl -sL kejilion.sh) docker install&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="_3frp"&gt;_3、frp &lt;a href="#_3frp" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.kejilion.pro/frp/" rel="external" target="_blank"&gt;教程&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/p&gt;</description></item><item><title>中央仓库上传指南</title><link>https://xiaoying.org.cn/pages/897f89/</link><pubDate>Sun, 23 Mar 2025 00:45:53 +0000</pubDate><guid>https://xiaoying.org.cn/pages/897f89/</guid><description>&lt;h2 id="heading"&gt;简介 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Maven 中央仓库是 Java 生态系统中最重要的依赖库之一，将你的项目发布到 Maven 中央仓库可以让全球的开发者更容易地使用你的库。本文将详细介绍如何将你的 Java 项目发布到 Maven 中央仓库的完整流程。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;前置条件 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;JDK 8 或更高版本&lt;/li&gt;
&lt;li&gt;Maven 3.0+&lt;/li&gt;
&lt;li&gt;GPG（用于签名）&lt;/li&gt;
&lt;li&gt;Sonatype OSSRH 账号&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;步骤概览 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;注册 Sonatype 账号&lt;/li&gt;
&lt;li&gt;配置 GPG 签名&lt;/li&gt;
&lt;li&gt;配置 Maven 的 &lt;code&gt;settings.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;配置项目的 &lt;code&gt;pom.xml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;发布到中央仓库&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="heading-3"&gt;详细步骤 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="-sonatype-"&gt;注册 Sonatype 账号 &lt;a href="#-sonatype-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;从 2024 年 3 月 12 日起，所有注册都将通过 &lt;a href="https://central.sonatype.com/" rel="external" target="_blank"&gt;Sonatype 中央门户网站&lt;svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"&gt;&lt;path fill="currentColor" d="M14 5c-.552 0-1-.448-1-1s.448-1 1-1h6c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1s-1-.448-1-1v-3.586l-7.293 7.293c-.391.39-1.024.39-1.414 0-.391-.391-.391-1.024 0-1.414l7.293-7.293h-3.586zm-9 2c-.552 0-1 .448-1 1v11c0 .552.448 1 1 1h11c.552 0 1-.448 1-1v-4.563c0-.552.448-1 1-1s1 .448 1 1v4.563c0 1.657-1.343 3-3 3h-11c-1.657 0-3-1.343-3-3v-11c0-1.657 1.343-3 3-3h4.563c.552 0 1 .448 1 1s-.448 1-1 1h-4.563z"/&gt;&lt;/svg&gt;&lt;/a&gt; 进行。&lt;/p&gt;</description></item><item><title>git设置代理</title><link>https://xiaoying.org.cn/pages/fb8363/</link><pubDate>Mon, 15 Jul 2024 00:06:11 +0000</pubDate><guid>https://xiaoying.org.cn/pages/fb8363/</guid><description>&lt;h2 id="git"&gt;git设置代理 &lt;a href="#git" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;1、打开clash开启代理&lt;/p&gt;
&lt;p&gt;2、系统设置代理&lt;/p&gt;
&lt;p&gt;​ 网络和Internet设置 -&amp;gt; 代理 -&amp;gt; 手动设置代理&lt;/p&gt;
&lt;p&gt;3、git设置代理&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="e4d778d" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global http.proxy 127.0.0.1:7890&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="617ccfe" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global https.proxy 127.0.0.1:7890&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="063d12a" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global https.proxy socks5 127.0.0.1:7890&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="3d9e704" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global https.proxy socks5 127.0.0.1:7890&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;4、查看git代理是否设置成功&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="cbe67fb" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global -l&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="c656c91" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global --get http.proxy&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="407b9a7" class="language-bash wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git config --global --get https.proxy&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;5、git取消代理&lt;/p&gt;</description></item><item><title>Java文件转换为Velocity模板</title><link>https://xiaoying.org.cn/pages/470255/</link><pubDate>Sun, 06 Apr 2025 16:42:45 +0000</pubDate><guid>https://xiaoying.org.cn/pages/470255/</guid><description>&lt;p&gt;将Java文件转换为Velocity模板需要进行以下几个方面的修改&lt;/p&gt;
&lt;h2 id="heading"&gt;文件扩展名 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;首先需要将文件扩展名从.java改为.java.vm，表示这是一个Velocity模板文件。&lt;/p&gt;
&lt;h2 id="heading-1"&gt;替换静态内容为动态变量 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;需要将Java文件中的静态内容替换为Velocity变量和指令。根据当前仓库中的模板，常用的Velocity变量有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;${packageName} - 包名的基础部分&lt;/li&gt;
&lt;li&gt;${moduleName} - 模块名称&lt;/li&gt;
&lt;li&gt;${subpackageName} - 子包名&lt;/li&gt;
&lt;li&gt;${entityName} - 实体类名称&lt;/li&gt;
&lt;li&gt;${lowerFirstEntityName} - 首字母小写的实体类名称&lt;/li&gt;
&lt;li&gt;${businessName} - 业务名称&lt;/li&gt;
&lt;li&gt;${author} - 作者名称&lt;/li&gt;
&lt;li&gt;${date} - 日期&lt;/li&gt;
&lt;li&gt;${tableName} - 数据库表名&lt;/li&gt;
&lt;li&gt;${fieldConfigs} - 字段配置列表&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="heading-2"&gt;添加条件判断和循环 &lt;a href="#heading-2" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;使用Velocity的条件判断和循环指令来处理动态内容：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="53437aa" class="language-velocity wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;#if(条件)
 // 条件成立时的内容
#else
 // 条件不成立时的内容
#end

#foreach($item in $collection)
 // 循环内容，可以使用$item访问当前项
#end&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-3"&gt;具体示例 &lt;a href="#heading-3" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以下是一个具体的转换示例&lt;/p&gt;
&lt;h3 id="java"&gt;原始Java文件： &lt;a href="#java" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="2342fa4" class="language-java wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;package com.example.project.controller;

import com.example.project.entity.User;
import com.example.project.service.UserService;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@RequestMapping(&amp;#34;/user&amp;#34;)
public class UserController {
 
 private UserService userService;
 
 // 其他代码
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="velocity"&gt;转换后的Velocity模板： &lt;a href="#velocity" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="b0c398a" class="language-velocity wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;package ${packageName}.${moduleName}.controller;

import ${packageName}.${moduleName}.model.entity.${entityName};
import ${packageName}.${moduleName}.service.${entityName}
Service;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
@RequestMapping(&amp;#34;/${lowerFirstEntityName}&amp;#34;)
public class ${entityName}Controller {
 
 private ${entityName}Service ${lowerFirstEntityName}Service;
 
 // 其他代码
}&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-4"&gt;处理字段和属性 &lt;a href="#heading-4" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;对于实体类中的字段和属性，需要使用#foreach循环遍历${fieldConfigs}，如当前仓库中的entity.java.vm模板所示：&lt;/p&gt;</description></item><item><title>暂停windows更新</title><link>https://xiaoying.org.cn/pages/b8b67c/</link><pubDate>Wed, 30 Jul 2025 09:46:59 +0000</pubDate><guid>https://xiaoying.org.cn/pages/b8b67c/</guid><description>&lt;h2 id="heading"&gt;打开注册表 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;按照路径打开如下注册表位置&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6c231ac" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading-1"&gt;修改配置文件 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;新建DWORD(32位)值(D)，名称填写&lt;code&gt;FlightSettingsMaxPauseDays&lt;/code&gt;，双击进行修改，右侧选10进制，值填写36254，点击确定，重启电脑，然后打开设置，打开windows更新侧边栏，点击暂停更新右侧小三角，等待片刻，即可发现可以延长更新最多5000多周&lt;/p&gt;</description></item><item><title>关联到已存在的 GitHub 仓库</title><link>https://xiaoying.org.cn/pages/7841b0/</link><pubDate>Mon, 28 Jul 2025 11:05:40 +0000</pubDate><guid>https://xiaoying.org.cn/pages/7841b0/</guid><description>&lt;h2 id="1--git-"&gt;1️⃣ 初始化本地项目为 Git 仓库 &lt;a href="#1--git-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果你的项目还没用 Git 管理，先在项目目录下初始化：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="78749c2" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git init&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="2-github-"&gt;2️⃣ 上传GitHub 远程仓库 &lt;a href="#2-github-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading"&gt;关联远程仓库 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;通过以下命令添加远程仓库&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="74a4a7a" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git remote add origin &amp;lt;Github url&amp;gt;&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;如果执行后 &lt;code&gt;git remote -v&lt;/code&gt; 发现有多个远程仓库，例如：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="6909e73" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;origin https://github.com/liyao52033/demo.git (fetch)
origin https://github.com/liyao52033/demo.git (push)
demo https://github.com/liyao52033/demo.git (fetch)
demo https://github.com/liyao52033/demo.git (push)&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;删除多余的远程仓库：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="61a0dcc" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git remote remove demo&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;再次检查：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="7d9bc1b" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git remote -v&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;输出应为：&lt;/p&gt;</description></item><item><title>Git双平台推送</title><link>https://xiaoying.org.cn/pages/b19439/</link><pubDate>Sat, 07 Mar 2026 19:01:12 +0000</pubDate><guid>https://xiaoying.org.cn/pages/b19439/</guid><description>&lt;p&gt;本文介绍如何在一个本地 Git 仓库中同时使用两个远程仓库：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;CNB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目标结构：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub：&lt;code&gt;main&lt;/code&gt;、&lt;code&gt;bg&lt;/code&gt; 等开发分支&lt;/li&gt;
&lt;li&gt;CNB：只保留 &lt;code&gt;main&lt;/code&gt; 分支&lt;/li&gt;
&lt;li&gt;本地开发：使用 &lt;code&gt;bg&lt;/code&gt; 分支&lt;/li&gt;
&lt;li&gt;同步规则：&lt;/li&gt;
&lt;/ul&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="08a2b6f" class="language-sh wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;本地 bg → GitHub bg
本地 bg → CNB main&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id="heading"&gt;一、远程仓库结构 &lt;a href="#heading" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id="heading-1"&gt;先看当前远程仓库 &lt;a href="#heading-1" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="5d10371" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git remote -v&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;一般会看到类似：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="8b1f4b2" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;origin https://github.com/xxx/your-project.git (fetch)
origin https://github.com/xxx/your-project.git (push)&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id="-cnb-"&gt;添加 CNB 远程仓库 &lt;a href="#-cnb-" class="anchor" aria-hidden="true"&gt;&lt;i class="material-icons align-middle"&gt;link&lt;/i&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;假设你的 CNB 仓库地址是：&lt;/p&gt;



















&lt;div class="prism-codeblock"&gt;
 &lt;pre id="a3b99ae" class="language- wrap-line-numbers" data-click-highlight="false" data-linenos="true" data-start="1"&gt;
 &lt;code&gt;git remote add cnb https://cnb.cool/xxx/your-project.git&lt;/code&gt;
 &lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;然后确认：&lt;/p&gt;</description></item></channel></rss>