7 커밋 d4bc20d90d ... 07002ff339

작성자 SHA1 메시지 날짜
  liuchuanwei 07002ff339 feat(mysql):合并旧有的mysql基础命令 4 달 전
  liuchuanwei 351ed96e23 feat(excel):新增excel使用技巧 4 달 전
  liuchuanwei 320ae750da feat(win11):新增win11桌面右键菜单还原 4 달 전
  liuchuanwei 6600bc20da feat(nodejs):新增nodejs学习总结 4 달 전
  liuchuanwei 4e65eace19 docs(s):修改文档细节 4 달 전
  liuchuanwei 40c7d7bc4f docs(backpack):合并旧有文章笔记 4 달 전
  liuchuanwei f21feda12f docs(idea):添加tomcat在idea中的使用总结 4 달 전
42개의 변경된 파일1854개의 추가작업 그리고 6개의 파일을 삭제
  1. 1 0
      git/Git和TortoiseGit安装配置指南.md
  2. 45 1
      ide/IDEA使用总结.md
  3. 16 1
      ide/Notepad++使用总结.md
  4. BIN
      ide/imgs/Pasted image 20240414095547.png
  5. BIN
      ide/imgs/Pasted image 20240414101521.png
  6. BIN
      ide/imgs/Pasted image 20240414111717.png
  7. BIN
      ide/imgs/Pasted image 20240414120748.png
  8. BIN
      ide/imgs/Pasted image 20240425145925.png
  9. BIN
      ide/imgs/Pasted image 20240425145935.png
  10. 115 0
      maven/JDK1.8安装指南.md
  11. 62 0
      maven/Maven安装使用指南.md
  12. 200 0
      maven/Maven私服搭建使用指南.md
  13. 4 0
      maven/Maven自定义archetype.md
  14. BIN
      maven/imgs/image-20200808162545096.png
  15. BIN
      maven/imgs/image-20200808162759278.png
  16. BIN
      maven/imgs/image-20200808163029711.png
  17. BIN
      maven/imgs/image-20200808172632992.png
  18. BIN
      maven/imgs/image-20200808172951319.png
  19. BIN
      maven/imgs/image-20200808173019643.png
  20. BIN
      maven/imgs/image-20200808175034963.png
  21. BIN
      maven/imgs/image-20200808183443418.png
  22. 1 1
      maven/如何配置maven编译插件的JDK版本.md
  23. 194 0
      mysql/MySQL常用命令.md
  24. 90 0
      nodejs/nodejs学习总结.md
  25. 1 0
      office/excel函数-VLOOKUP使用.md
  26. 1 0
      office/excel数组.md
  27. 48 0
      python/python爬取微信公众号历史消息.md
  28. 18 0
      python/python问题总结.md
  29. 1 1
      webserver/Nginx服务器.md
  30. BIN
      webserver/imgs/Image_20200819141049.jpg
  31. 230 0
      webserver/使用Nginx解决前端跨域问题.md
  32. 12 0
      windows/win11右键菜单还原.md
  33. 2 0
      中间件/ES基础查询语法.md
  34. 310 0
      中间件/RabiitMQ3.7.24主从环境搭建指南.md
  35. 30 0
      前端/JS中的位置和宽度:clientWidth、offsetWidth、scrollWidth 等的区别.md
  36. 35 0
      前端/JavaScript和Jquery插件开发指南.md
  37. 72 0
      前端/css文件超长自动滚动.md
  38. BIN
      前端/imgs/Pasted image 20240425134406.png
  39. 183 0
      前端/js基础语法.md
  40. 24 0
      前端/js常用函数.md
  41. 0 2
      前端/nodejs.md
  42. 159 0
      前端/鼠标滚轮滚动翻页.md

+ 1 - 0
git/Git和TortoiseGit安装配置指南.md

@@ -115,6 +115,7 @@ git config user.name
 
 ## SSH服务
 
+*使用SSH服务的前提是:具有访问SSH端口22的权限*
 ### 配置 Git SSH 密钥
 
 1. 进入GIT_HOME/usr/bin 目录下,执行以下命令,生成 SSH 公私钥

+ 45 - 1
ide/IDEA使用总结.md

@@ -66,4 +66,48 @@ IDEA除了可以对整个进程Debug外,还可以对每个线程进行Debug,
 
 **BookCatalog**
 
-![image-20201102181546719](imgs/image-20201102181546719.png)
+![image-20201102181546719](imgs/image-20201102181546719.png)
+
+
+## Tomcat使用
+参考:
+[IntelliJ IDEA 的 Project Structure 窗口中的 Artifacts 勾选 Include in project build](https://blog.csdn.net/liaowenxiong/article/details/122136877)
+[IDEA中Facets和Artifacts配置说明](https://blog.csdn.net/qq_38721734/article/details/110259125)
+[idea中artifacts、facets、modules](https://zhuanlan.zhihu.com/p/365027697)
+[IntelliJ IDEA 部署 Web 项目,终于搞懂了](https://segmentfault.com/a/1190000022563954)
+[IntelliJ IDEA在应用服务器上更新应用](https://www.w3cschool.cn/intellij_idea_doc/intellij_idea_doc-q3uc2wy4.html)
+
+传统SpringMvc项目目录和对应tomcat配置如下:
+![[Pasted image 20240414101521.png]]
+![[Pasted image 20240414095547.png]]
+
+在日常开发过程中,我们修改完java代码后,接着就点击 Build 编译,然后就可以去验证代码了(前提是 On 'Update' Action 选择了 Update classes and resources)
+
+但是修改JSP的时候遇到一个问题:**每次修改完JSP文件后,都必须重启tomcat才能使应用的页面生效**。仅仅点击Build(Build Project)是不能使JSP页面生效的。
+原因是 Build 不是 'Update' Action,无法触发 Update classes and resoures 。
+
+方法1:可以Ctrl + F10 或者点击 Update Tomcat Application 实现触发,这时会有弹框提示。
+![[Pasted image 20240414120748.png]]
+
+方法2:**如果要使JSP页面或者说是 webapp 目录下的修改生效,就需要点击 Build 下的 Build Artifact**。其实这步操作就是 Tomcat配置 Before launch 中的 Build 'favor-bill:war exploded' artifact,即重新构建war包,将classes和resources、webapp目录复制到 target 目录中。
+
+方法3:另外还有一种方法将 Build Artifact 和 Build 合二为一。即在 Project Setting 的 Artifacts 勾选 Include in project build,意为在 Build 的时候构建artifact。
+
+![[Pasted image 20240414111717.png]]
+
+注:IDEA中web应用的配置都在 Project Structure。
+
+
+还有一个问题,百思不得其解。当启动tomcat后,在 target 和 target/favor-bill-1.0-SNAPSHOT/WEB-INF 下各有1个classes文件夹。而当点击Build后,只会将修改的java文件重新编译到 target/classes 文件夹下,WEB-INF/classes里的class文件没变。这个时候修改的代码在web应用里竟然生效了。
+那么IDEA中启动tomcat应用时,生效的是  target/classes 还是 target/favor-bill-1.0-SNAPSHOT/WEB-INF/classes呢???
+
+## Java文件显示带J文件
+
+Java文件图标变成下面这样,而且包也没有分层。
+![](Pasted%20image%2020240425145925.png)
+**解决方法:**
+
+打开 “Project” 中的 “Project Structure”
+![](Pasted%20image%2020240425145935.png)
+
+点击删除后,重新 “Add Content Root” 。

+ 16 - 1
ide/Notepad++使用总结.md

@@ -2,4 +2,19 @@
 
 
 ### JSON Viewer
-在线安装,移动plugin的插件即可
+在线安装,移动plugin的插件即可
+
+
+# 添加语法
+
+> notepad++是一款很笨重并且支持代码高亮显现的文本修改软体,只不过内置的代码高亮语法不包罗nginx.conf
+
+## Nginx 配置文件高亮显示
+
+1. 下载语言文件 https://file.bugxia.com/s/NSdf3mi3NrbfqiY
+
+2. 打开Notepad++,选择“语言” -> 自定义语言格式,点击”导入“按钮,将下载的语言文件导入
+
+3. 重启Notepad++,打开nginx配置文件,选择“语言” -> Nginx 
+
+    

BIN
ide/imgs/Pasted image 20240414095547.png


BIN
ide/imgs/Pasted image 20240414101521.png


BIN
ide/imgs/Pasted image 20240414111717.png


BIN
ide/imgs/Pasted image 20240414120748.png


BIN
ide/imgs/Pasted image 20240425145925.png


BIN
ide/imgs/Pasted image 20240425145935.png


+ 115 - 0
maven/JDK1.8安装指南.md

@@ -0,0 +1,115 @@
+[TOC]
+
+<!-- toc -->
+
+# Oracle JDK1.8 下载安装
+
+> 关于 JDK8 收费的问题:
+>
+> 如果你的公司已经买了这个Java SE Advanced (或者 Advanced Desktop), Java SE Suite的License, 什么都不用担心,你很安全。
+> 如果你的公司正在使用Oracle JDK 8 并且还想在2019年1月之后获得那些更新和支持,你需要购买Orace 的订阅服务。
+> 如果你的公司一直在在升级你的Oracle JDK ,比如说已经升级到JDK9了,你什么服务都不用购买, 因为那个订阅服务主要解决的是老版本的Update 的问题。
+> 或者可以选择一个没有public update的Oracle JDK , 这也很常见,很多JDK已经非常稳定了, 比如Oracle JDK 7 发布日期是2011年7月, “End of Public Updates” 是2015年4月, 我估计现在还有不少公司还在使用JDK7这个已经没有public update的版本吧!
+> 如果真的出现了巨大的安全漏洞,你又没法升级JDK ,那只好去购买订阅服务去Fix了。
+> 当然,你的公司也可以选择纯开源OpenJDK。
+>
+> [JDK8的发布日志](https://www.oracle.com/java/technologies/javase/8all-relnotes.html)
+
+## 下载
+
+1. [Oracle Java 下载页面](https://www.oracle.com/java/technologies/javase-downloads.html) 
+
+2. 点击页面下方的 [Java Archive](https://www.oracle.com/java/technologies/oracle-java-archive-downloads.html) 选择其他版本
+
+    ![image-20200808172632992](imgs/image-20200808172632992.png)
+
+    ![image-20200808173019643](imgs/image-20200808173019643.png)
+
+3. https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
+
+    选择合适的JDK版本下载
+
+## Centos7 下安装
+
+1. 解压
+
+    ```shell
+    #解压
+    tar -zxvf jdk-8u152-linux-x64.tar.gz -C /usr/local/
+    ```
+    
+2. 配置环境变量
+
+    ```shell
+    vim /etc/profile
+    #在末尾添加
+    export JAVA_HOME=/usr/local/jdk1.8.0_152
+    export JRE_HOME=${JAVA_HOME}/jre
+    export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
+    export PATH=${JAVA_HOME}/bin:$PATH
+    
+    #使环境变量生效
+    source /etc/profile
+    ```
+3. 测试
+
+    ```shell
+    java -version
+    ```
+
+## Windows 下安装
+
+# Open JDK1.8 下载安装
+
+## 下载
+
+[OpenJDK官网](https://jdk.java.net/)
+
+[OpenJDK官网下载地址](https://jdk.java.net/java-se-ri/8-MR3) *(官网貌似没有 OpenJDK 64位 版本)*
+
+![image-20200808175034963](imgs/image-20200808175034963.png)
+
+## Centos7 下安装
+
+1. 解压
+
+    ```shell
+    tar -zxvf openjdk-8u41-b04-linux-x64-14_jan_2020.tar.gz -C /usr/local/
+    ```
+
+    会生成  `/usr/local/java-se-8u41-ri`
+
+2. 配置环境变量
+
+   ```shell
+   vi /etc/profile
+   #在末尾添加
+   export JAVA_HOME=/usr/local/java-se-8u41-ri
+   export JRE_HOME=${JAVA_HOME}/jre
+   export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
+   export PATH=${JAVA_HOME}/bin:$PATH
+   
+   #使环境变量生效
+   source /etc/profile
+   ```
+
+3. 测试
+
+    ```shell
+    java -version
+    openjdk version "1.8.0_41"
+    OpenJDK Runtime Environment (build 1.8.0_41-b04)
+    OpenJDK 64-Bit Server VM (build 25.40-b25, mixed mode)
+    ```
+
+    
+
+## Windows 下安装
+
+1. 解压
+
+2. 配置环境变量
+    * 添加环境变量 JAVA_HOME:C:\Program Files\java-se-8u41-ri\
+    * 追加环境变量path:`;%JAVA_HOME%bin`
+    * 添加环境变量 CLASSPATH:`.;%JAVA_HOME%lib\dt.jar;%JAVA_HOME%lib\tools.jar;`
+3. cmd下输入 `java -version` 测试

+ 62 - 0
maven/Maven安装使用指南.md

@@ -0,0 +1,62 @@
+# 下载
+
+> 参考:
+* [Apache Maven  安装说明](https://maven.apache.org/install.html)
+* [Apache Maven 最新版本](https://maven.apache.org/download.cgi)
+* [Apache Maven 历史版本详情](https://maven.apache.org/docs/history.html)
+* [Apache Maven 历史版本下载](https://archive.apache.org/dist/maven/maven-3/)
+
+下载 apache-maven-3.x.x-bin.zip 
+
+# 安装
+
+2. 解压
+
+2. 追加环境变量path
+
+   `;MAVEN_HOME/bin`
+
+   > 不用再设置  M2_HOME 或 MAVEN_HOME 了
+
+3. CMD命令行下 `mvn -v` 测试
+
+# 使用
+
+## 无网络下使用 Maven 
+
+1. 本地仓库一定要存在需要的jar包
+
+2. 设置本地仓库
+
+   ```xml
+   <settings>
+   	...
+       <localRepository>E:\wokesoftware\maven-repository</localRepository>
+       ...
+   </settings>
+   ```
+
+3. 把镜像地址指向本地仓库
+
+   ```xml
+   <settings>
+   	...
+       <mirrors>
+           <mirror>
+               <id>central</id>
+               <name>central</name>
+               <!-- 将镜像地址设置为本地maven地址 -->
+               <url>file://E:\wokesoftware\maven-repository</url>
+               <mirrorOf>*</mirrorOf>
+           </mirror>
+       </mirrors>
+       ...
+   </settings>
+   ```
+
+> 常见问题:
+>
+> Failure to transfer $groupId:$artifactId:pom:$version from $centralUrl was cached in the local repository, resolution will not be reattempted until the update interval of alimaven has elapsed or updates are forced。Original error: Could not transfer artifact $groupId:$artifactId:pom:$version  from/to central ($centralUrl):repo.maven.apache.org
+>
+> 解决方案:有可能就是联网的问题
+

+ 200 - 0
maven/Maven私服搭建使用指南.md

@@ -0,0 +1,200 @@
+> Tip:Nexus 是典型的 JavaWeb 应用,所以**安装nexus之前一定要安装jdk环境**
+>
+> 参考:
+>
+> * 《maven实战》第9章和第6章
+
+# 下载
+
+> 官网下载太慢,百度云盘下载:
+>
+> 链接:https://pan.baidu.com/s/1ihdAkVfQbfdcl6KIlgQtxQ
+> 提取码:tpxt
+
+[Nexus官网下载地址](https://www.sonatype.com/download-oss-sonatype)
+
+![image-20200808162545096](imgs/image-20200808162545096.png)
+
+![image-20200808162759278](imgs/image-20200808162759278.png)
+
+[Nexus历史版本下载](https://help.sonatype.com/repomanager3/download/)
+
+![image-20200808163029711](imgs/image-20200808163029711.png)
+
+
+
+# Centos7 下安装
+
+1. 解压
+
+    ```shell
+    tar -zxvf nexus-3.18.1-01-unix.tar.gz -C /usr/local
+    ```
+
+    解压后2个目录:nexus-3.18.1-01 和 sonatype-work(后者是nexus的工作目录)
+
+2. 启动
+
+    ```shell
+    cd /usr/local/nexus-3.18.1-01/bin
+    ./nexus run
+    ```
+
+    > Nexus 就是一个JavaWeb应用,所以启动过程和普通的JavaWeb一样。
+
+3. 访问 nexus
+
+    ip和端口配置 NEXUS_HOME\nexus-3.18.1-01\etc\nexus-default.properties 中
+
+
+
+# Windows 下安装
+
+1. 解压
+
+   解压后2个目录:nexus-3.18.1-01 和 sonatype-work(后者是nexus的工作目录)
+
+2. 启动
+
+   进入 NEXUS_HOME/nexus-3.18.1-01/bin 中,cmd命令行中执行  `nexus.exe /run` 
+
+3. 访问 nexus [http://localhost:8081](http://localhost:8081)
+
+   ip和端口配置 NEXUS_HOME\nexus-3.18.1-01\etc\nexus-default.properties 中
+
+
+
+# 私服的简单使用
+
+## 1. 用户-角色-权限
+
+nexus 预定义了 admin 用户,拥有对 nexus 完全控制的权限。密码在登录框中会有所提示。首次登录后就被要求修改密码。
+
+## 2. Nexus 仓库
+
+nexus 有三种仓库类型:proxy、hosted、group(整合多个仓库)
+
+nexus 内置了以下几种仓库:
+
+![image-20200808183443418](imgs/image-20200808183443418.png)
+
+## 3. 远程仓库下载配置
+
+pom.xml 当前项目有效
+
+```xml
+..
+<repositories>
+    <repository>
+        <id>nexus</id>
+        <name>Nexus</name>
+        <url>http://192.168.1.3:8200/repository/maven-public/</url>
+        <releases>
+            <enabled>true</enabled>
+            <updatePolicy>daily</updatePolicy>
+        </releases>
+        <snapshots>
+            <enabled>false</enabled>
+        </snapshots>
+    </repository>
+</repositories>
+<pluinRepositories>
+    <pluginRepository>
+        <id>nexus</id>
+        <name>Nexus</name>
+        <url>http://192.168.1.3:8200/repository/maven-public/</url>
+        <releases>
+            <enabled>true</enabled>
+        </releases>
+        <snapshots>
+            <enabled>false</enabled>
+        </snapshots>
+    </pluginRepository>
+</pluinRepositories>
+..
+```
+
+settings.xml (所有项目有效)
+
+```xml
+...
+<profiles>
+    <profile>
+    	<id>nexus</id>
+        <repositories>
+            <repository>
+                <id>nexus</id>
+                <name>Nexus</name>
+                <url>http://192.168.1.3:8200/repository/maven-public/</url>
+                <releases>
+                    <enabled>true</enabled>
+                    <updatePolicy>daily</updatePolicy>
+                </releases>
+                <snapshots>
+                    <enabled>false</enabled>
+                </snapshots>
+            </repository>
+        </repositories>
+        <pluinRepositories>
+            <pluginRepository>
+                <id>nexus</id>
+                <name>Nexus</name>
+                <url>http://192.168.1.3:8200/repository/maven-public/</url>
+                <releases>
+                    <enabled>true</enabled>
+                </releases>
+                <snapshots>
+                    <enabled>false</enabled>
+                </snapshots>
+            </pluginRepository>
+        </pluinRepositories>
+    </profile>
+</profiles>
+<activeProfiles>
+	<activeProfile>nexus</activeProfile>
+</activeProfiles>
+...
+```
+
+## 4. 远程仓库上传配置
+
+pom.xml
+
+```xml
+...
+<distributionManagement>
+	<repository>
+    	<id>nexus-releases</id>
+        <name>Nexus Releases Repository</name>
+        <url>http://192.168.1.3:8200/repository/maven-releases/</url>
+    </repository>
+    <snapshotRepository>
+        <id>nexus-snapshots</id>
+        <name>Nexus Snapshots Repository</name>
+        <url>http://192.168.1.3:8200/repository/maven-snapshots/</url>
+    </repository>
+    </snapshotRepository>
+</distributionManagement>
+...
+```
+
+## 5. 私服配置
+
+私服+镜像 = 绝配
+
+settings.xml
+
+```xml
+...
+<mirrors>
+	<mirror>
+    	<id>nexus</id>
+        <url>http://192.168.1.3:8200/repository/maven-public/</url>
+        <mirrorOf>*</mirrorOf>
+    </mirror>
+</mirrors>
+...
+```
+
+
+

+ 4 - 0
maven/Maven自定义archetype.md

@@ -1,3 +1,7 @@
+参考:
+* [架构师必备技能:Maven Archetype生成项目模板](https://cloud.tencent.com/developer/article/1875305)
+* 书籍《Maven实战》
+* [Maven的这三个用法你一定要会](https://mp.weixin.qq.com/s/dXuCWQ_I6AVpV80ho-6b5A)
 1、创建好原型项目后 springmvc-simple,在项目根目录下执行
 ```shell
 mvn archetype:create-from-project

BIN
maven/imgs/image-20200808162545096.png


BIN
maven/imgs/image-20200808162759278.png


BIN
maven/imgs/image-20200808163029711.png


BIN
maven/imgs/image-20200808172632992.png


BIN
maven/imgs/image-20200808172951319.png


BIN
maven/imgs/image-20200808173019643.png


BIN
maven/imgs/image-20200808175034963.png


BIN
maven/imgs/image-20200808183443418.png


+ 1 - 1
maven/如何配置maven编译插件的JDK版本.md

@@ -28,7 +28,7 @@ maven有2种方法设置编译JDK版本,比如配置为 Java 1.8 版本
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
-        <version>3.10.1</version>
+        <version>3.13.1</version>
         <configuration>
           <source>1.8</source>
           <target>1.8</target>

+ 194 - 0
mysql/MySQL常用命令.md

@@ -0,0 +1,194 @@
+## MySQL 用户
+
+```sql
+-- 登录
+mysql -u<用户名> -p[密码] 
+-- 修改密码
+mysqladmin -u<用户名> -p[密码] password <new_password>   
+```
+
+## 数据库
+
+>MySQL数据库中的 UTF8 编码使用3个字节存储字段,无法存储emoji 表情这样的字段数据。
+>MySQL5.5.3+ 后来加入了 utf8mb4 支持,完全兼容 utf8。utf8mb4 最多使用4个字节存储字符,这样就可以存储emoji表情了。
+>Tip:
+> * jdbc url 中不要加 characterEncoding=UTF-8 或者 characterEncoding=UTF8MB4。连接器会自动识别字符编码的。
+> * utf8mb4 对MySQL 版本要求最低 5.5.3
+> * utf8mb4 对 jdbc mysql驱动版本最低 5.1.41
+
+```sql
+-- 显示所有的数据库
+show databases;
+
+-- 创建数据库,设置字符集utf8mb4,校对集 utf8mb4_general_ci,支持emoj表情
+create database db_name default character set utf8mb4 collate utf8mb4_general_ci;
+
+-- 查看创建数据库的语句
+show create database db_name;
+```
+
+## 备份和恢复
+
+```sql
+-- 导出数据库(注意:当前命令是在cmd命令行下执行)
+mysqldump -u<用户名> -p[密码] db_name > filename
+
+-- 恢复
+-- 1.先创建一个数据库
+create database db_name default character set utf8 collate utf8_general_ci;
+-- 2.使用该数据库
+use db_name;
+-- 3.导入数据库数据
+source filename;
+```
+
+
+## 表操作
+
+```sql
+-- 创建表
+create table if not exists student(
+	id int(11) primary key auto_increment,
+	name varchar(50) unique not null,
+	age tinyint(2) comment '年龄',
+	sex tinyint(1) default 0 comment '0男1女'
+) ENGINE=INNODB comment '学生表';
+
+-- 查看创建表的原始语句
+show create table table_name;
+
+-- 查看表结构
+desc table_name;
+
+-- 查看所有表
+show tables;
+
+-- 删除表
+drop table table_name;
+drop table if exists table_name;
+
+-- 重命名表
+alter table table_name rename new_table_name;
+
+```
+
+## 列操作
+
+```sql
+-- 添加列
+alter table table_name add column column_name int not null;
+
+-- 删除列
+alter table table_name drop column column_name;
+
+-- 修改列属性
+alter table table_name modify column column_name float not null;
+
+-- 修改列
+alter table table_name change column column_name_1 column_name2 float default 0;
+```
+
+## 索引
+
+```sql
+-- 添加索引
+alter table table_name add index ind_column_name(column_name);
+create index ind_column_name on table_name(column_name);
+
+-- 删除索引
+alter table table_name drop index ind_column_name;
+drop index ind_column_name on table_name(column_name);
+
+-- 查看索引
+show index from table_name;
+
+--  PS1:索引是不可修改的,只能删除后再创建
+--  PS2:对表记录的删除会造成索引的存储碎片,过多的存储碎片不仅占用存储空间,还会降低数据库运行速度。重建索引能够有效的进行“碎片整理”。
+--  查看索引存储碎片(当 Data_free 列值大于0时表示有碎片,值越大碎片越多)
+show table status like 'table_name';
+
+```
+
+## 增删改查
+
+```sql
+-- 插入
+insert into student(id, name, age, sex) values(1, '小明', 23, 0);
+-- 批量插入
+insert into student(name, age, sex) values
+('小强', 18, 0),
+('小华', 28, 1),
+('小张', 23, 1);
+
+-- 删除
+delete from student where id=1;
+
+-- 更新
+update student set age=24 where id=2;
+
+-- 查询
+select * from student;
+```
+
+## 日期时间转换
+```sql
+-- 当前时间
+select now(); -- 结果:2024-04-10 08:41:12
+select sysdate(); -- 结果:2024-04-10 08:41:12
+-- sysdate() 日期时间函数跟 now() 类似,不同之处在于:now() 在执行开始时值就得到了, sysdate() 在函数执行时动态得到值;
+
+-- 当前时间戳
+select current_timestamp, current_timestamp();
+
+-- 日期转为字符串
+select date_format(sysdate, '%Y%m%d%H%i%s');
+-- 时间转为字符串
+select time_format(now(), '%Y%m%d%H%i%s');
+
+-- 字符串转为日期
+select str_to_date('2024-01-01', '%Y-%m-%d');
+select str_to_date('2024-01-01 08:30:12', '%Y-%m-%d %h:%i:%s');
+```
+
+## 插入的特殊操作
+### INSERT SELECT
+```sql
+-- 给所有女学生插入一条礼品记录  
+INSERT INTO student_gift(student_id, gift)   
+SELECT id, '手绳' as gift   
+FROM student   
+WHERE sex=1 ;  
+```
+
+### INSERT FROM
+```sql
+-- 将 student 表数据复制到 student_bak 表  
+INSERT INTO student_bak FROM student ;
+```
+
+
+## 更新的特殊操作
+
+### 更新值为null
+
+```sql
+-- 直接设置等于常量null
+update student s set s.age=null where s.id=3;
+```
+注意:
+如果列设置了NOT NULL,必须先修改这个列的属性。否则会报错:1048 - Column 'name' cannot be null
+
+### 替换字符
+```sql
+-- 将 student 表字段 name 中的 '小' 全部替换成 '大'  
+UPDATE student SET name=REPLACE(name, '小', '大') WHERE name LIKE '%小%' ;
+```
+
+### 关联更新
+```sql
+-- 将student_bak表的字段更新到student表中  
+UPDATE student s
+JOIN student_bak b 
+	ON b.id=s.id  
+SET s.name=b.name, s.age=b.age;
+```

+ 90 - 0
nodejs/nodejs学习总结.md

@@ -0,0 +1,90 @@
+## 安装Nodejs
+1. 下载安装包并安装,官网地址:https://nodejs.org/en
+2. 打开CMD,输入 node -v 验证是否安装成功
+
+## 关于NPM
+
+NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
+- 允许用户从NPM服务器**下载别人编写的第三方包**到本地使用。
+* 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
+- 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
+新版的nodejs已经集成了npm,所以安装了nodejs也就一同安装了npm。可以通过输入 **"npm -v"** 来测试是否成功安装,出现版本提示表示安装成功。
+
+### 升级npm
+```shell
+# 升级到最新版本
+npm install npm -g
+# 升级到指定版本
+npm install npm@6.14.13 -g
+```
+
+### npm镜像
+
+由于国内直接使用 npm 的官方镜像是非常慢的,这里推荐使用淘宝 NPM 镜像。
+
+npm 官方原始镜像网址是:https://registry.npmjs.org/
+淘宝 NPM 镜像:https://registry.npm.taobao.org
+阿里云 NPM 镜像:https://npm.aliyun.com
+腾讯云 NPM 镜像:https://mirrors.cloud.tencent.com/npm/
+华为云 NPM 镜像:https://mirrors.huaweicloud.com/repository/npm/
+网易 NPM 镜像:https://mirrors.163.com/npm/
+中国科学技术大学开源镜像站:http://mirrors.ustc.edu.cn/
+清华大学开源镜像站:https://mirrors.tuna.tsinghua.edu.cn/
+
+```shell
+# 查看当前使用的镜像
+npm config get registry
+# 配置镜像
+npm config set registry https://registry.npm.taobao.org
+```
+
+淘宝 NPM 镜像是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。
+你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:
+```shell
+npm install -g cnpm --registry=https://registry.npmmirror.com
+```
+这样就可以使用 cnpm 命令来安装模块了:
+```shell
+cnpm install [name]
+```
+更多信息可以查阅:[https://npmmirror.com/](https://npmmirror.com/)
+
+### 本地安装和全局安装
+```shell
+# 本地安装
+npm install express
+# 全局安装
+npm install express -g
+```
+> Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。使用 Express 可以快速地搭建一个完整功能的网站。
+
+**本地安装:**
+1、将安装包放在 ./node_modules 下(运行npm命令时所在的目录)
+2、可以通过 require() 来引入本地安装的包
+
+**全局安装:**
+1、将安装包放在 /usr/local 下或者 node 的安装目录。
+2、可以直接在命令行里使用。
+
+**区别:**
+全局安装的包一般可提供直接执行的命令。我们通过对一些工具类的包采用这种方式安装,如:gulp, nodemon, live-server, nrm等。
+本地安装的包是与具体的项目有关的, 我们需要在开发过程中使用这些具体的功能。
+
+一个经验法则:要用到该包的命令执行任务的就需要全局安装;要通过require引入使用的就需要本地安装-项目包。
+
+**注:在项目中不能引用全局安装的包**
+
+### npm相关命令
+```shell
+# 卸载本地安装的模块
+npm uninstall 模块名
+# 查看本地安装的模块列表
+npm ls
+# 更新模块
+npm update 模块名
+# 搜索模块
+npm search 模块名
+
+
+```
+

+ 1 - 0
office/excel函数-VLOOKUP使用.md

@@ -0,0 +1 @@
+参考:[Vlookup函数的使用方法和实操案例](https://www.zhihu.com/tardis/zm/art/535042769?source_id=1005)

+ 1 - 0
office/excel数组.md

@@ -0,0 +1 @@
+参考:[EXCEL 数组公式及应用)](https://zhuanlan.zhihu.com/p/47003249)

+ 48 - 0
python/python爬取微信公众号历史消息.md

@@ -0,0 +1,48 @@
+**准备:**
+
+- 公众号历史消息的请求地址
+- cookie
+
+**2种方法获取地址和cookie**
+
+1. 用浏览器打开公众号历史消息页面,使用开发工具获取请求地址和cookie
+2. 用抓包工具获取请求地址和cookie,比如 Fidder、charles
+
+源码如下:
+```python
+# -*- coding: utf-8 -*-  
+import requests  
+import jsonpath  
+import json  
+   
+headers = {  
+    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",  
+    "Host": "mp.weixin.qq.com",  
+    "Referer": "https://mp.weixin.qq.com",  
+	# 设置好cookie  
+    "Cookie": "RK=c+zMAuktP8; ptcz=005f33a36542502454b119382853de0d9ea6aa693367c6ae312a1c34c0dcfebe; pgv_pvi=4737076224; ptui_loginuin=1254428526; pgv_pvid=3106019708; wxuin=1411706915; devicetype=Windows7; version=62070152; lang=zh_CN; pass_ticket=FyE/xFBG3nyqQokgb6OoN9VFXaZVJPK53op9NWOsmqB2HZm8CUhy5Hz9+fgVo+PA; wap_sid2=CKPgk6EFElxuY2VlWndUVWJjT1d2YnVzcXMxTk4xcldfQ3hVQUYzUnB1LTVZTDlyQkVCb2ZPZHQ2S3hXbUdsMEJ0VkNVdDBZUmJXUC0wb0ZUb1N6U0JVSlYybHdGZ29FQUFBfjCJsKjuBTgNQJVO"  
+           }  
+   
+for i in range(10):  
+    # 设置请求地址  
+	url = "https://mp.weixin.qq.com/mp/profile_ext?action=getmsg&__biz=MjM5Mjg3MTIzMQ==&f=json&offset={}&count=10&is_ok=1&scene=124&uin=777&key=777&pass_ticket=&wxtoken=&appmsg_token=1034_N22Qb3TiIEjqcdGLa-1KO9dkAZgO1e2zBcGB5w~~&x5=0&f=json".format(str(i * 10))  
+	  
+	response = requests.get(url, headers = headers)  
+   
+	res = response.json()  
+	  
+	# 此处要根据具体的json结构进行解析  
+	jsonRes = json.loads(res['general_msg_list'])  
+	titleList = jsonpath.jsonpath(jsonRes, "$..title")  
+	urlList = jsonpath.jsonpath(jsonRes, "$..content_url")  
+  
+	  
+	# 遍历 构造可存储字符串·  
+	for index in range(len(titleList)):  
+		title = titleList[index]  
+		url = urlList[index]  
+   
+		scvStr = "%s,%s,\n" % (title, url)  
+		with open("info.csv", "a+", encoding="gbk", newline='') as f:  
+			f.write(scvStr)
+```

+ 18 - 0
python/python问题总结.md

@@ -0,0 +1,18 @@
+
+### ModuleNotFoundError: No module named ‘requests’
+
+原因:没有导入requests库  
+解决方法:
+
+1. 打开cmd,进入PYTHON_HOME\\Scripts 目录
+2. 执行命令 `pip install requests`
+
+### Python安装pip出错:no matching distribution found for xxx
+
+解决方法:
+
+1. 打开cmd,进入PYTHON_HOME\\Scripts 目录
+2. 执行命令 `easy_install pip` 来安装pip
+3. 更新pip的版本 `easy_install --upgrade pip`
+
+

+ 1 - 1
webserver/Nginx服务器.md

@@ -60,7 +60,7 @@ make install
 
 安装成功后,会自动生成一个nginx目录
 
-## 3. 启动nginx
+## 3.启动nginx
 
 * 测试配置文件
 ```

BIN
webserver/imgs/Image_20200819141049.jpg


+ 230 - 0
webserver/使用Nginx解决前端跨域问题.md

@@ -0,0 +1,230 @@
+**前端同事**在 http://localhost:8080/index.html 页面中 ajax 请求 http://10.18.226.160:8091/system/sysPageType/find ,提示跨域错误
+
+![跨域错误](./imgs/Image_20200819141049.jpg)
+
+# 1. 使用CORS策略
+
+方法1:添加一个拦截器,给所有的请求响应添加跨域请求头
+
+```java
+@Component
+public class SimpleCORSFilter implements Filter {
+
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+        HttpServletResponse response = (HttpServletResponse) res;
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
+        response.setHeader("Access-Control-Max-Age", "3600");
+        response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
+        chain.doFilter(req, res);
+    }
+
+    public void init(FilterConfig filterConfig) {}
+
+    public void destroy() {}
+}
+```
+
+方法2:在SpringBoot项目中使用@CrossOrigin注解
+
+```java
+@RestController
+@RequestMapping("/account")
+public class AccountController {
+
+    @CrossOrigin
+    @GetMapping("/{id}")
+    public Account retrieve(@PathVariable Long id) {
+        // ...
+    }
+
+    @DeleteMapping("/{id}")
+    public void remove(@PathVariable Long id) {
+        // ...
+    }
+}
+```
+
+或者在 Controller 类上添加 
+
+```java
+@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
+```
+
+其中@CrossOrigin中的2个参数:
+
+**origins** : 允许可访问的域列表
+
+**maxAge**:准备响应前的缓存持续的最大时间(以秒为单位)。
+
+# 2. 服务器代理
+
+```nginx
+location /sys-web {
+	add_header 'Access-Control-Allow-Origin' $http_origin;
+	add_header 'Access-Control-Allow-Credentials' 'true';
+	add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+	add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+	add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+	if ($request_method = 'OPTIONS') {
+		add_header 'Access-Control-Max-Age' 1728000;
+		add_header 'Content-Type' 'text/plain; charset=utf-8';
+		add_header 'Content-Length' 0;
+		return 204;
+	}
+	root   html;
+	index  index.html index.htm;
+	proxy_pass http://127.0.0.1:8080;
+	proxy_set_header Host $host;
+	proxy_set_header X-Real-IP $remote_addr;
+	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+	proxy_set_header X-Forwarded-Proto $scheme;
+	proxy_connect_timeout 5;
+}
+```
+
+关键的就是下面这几行
+
+```nginx
+	add_header 'Access-Control-Allow-Origin' $http_origin;
+	add_header 'Access-Control-Allow-Credentials' 'true';
+	add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+	add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
+	add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+	if ($request_method = 'OPTIONS') {
+		add_header 'Access-Control-Max-Age' 1728000;
+		add_header 'Content-Type' 'text/plain; charset=utf-8';
+		add_header 'Content-Length' 0;
+		return 204;
+	}
+```
+
+说明:
+
+1、Access-Control-Allow-Origin,这里使用变量 $http_origin取得当前来源域,大家说用“*”代表允许所有,我实际使用并不成功,原因未知;
+
+2、Access-Control-Allow-Credentials,为 true 的时候指请求时可带上Cookie,自己按情况配置吧;
+
+3、Access-Control-Allow-Methods,OPTIONS一定要有的,另外一般也就GET和POST,如果你有其它的也可加进去;
+
+4、Access-Control-Allow-Headers,这个要注意,里面一定要包含自定义的http头字段(就是说前端请求接口时,如果在http头里加了自定义的字段,这里配置一定要写上相应的字段),从上面可看到我写的比较长,我在网上搜索一些常用的写进去了,里面有“web-token”和“app-token”,这个是我项目里前端请求时设置的,所以我在这里要写上;
+
+5、Access-Control-Expose-Headers,可不设置,看网上大致意思是默认只能获返回头的6个基本字段,要获取其它额外的,先在这设置才能获取它;
+
+6、语句“ if ($request_method = 'OPTIONS') { ”,因为浏览器判断是否允许跨域时会先往后端发一个 options 请求,然后根据返回的结果判断是否允许跨域请求,所以这里单独判断这个请求,然后直接返回;
+
+
+
+nginx add_header 指令说明:
+
+add_header 指令用来设置response的 header的。
+
+[官方文档](http://nginx.org/en/docs/http/ngx_http_headers_module.html) 中对 add_header 的解释
+
+>  Syntax:   **add_header** *name value* [always];
+>  Default:  —                                              |
+>  Context:  `http`, `server`, `location`, `if in location` 
+>
+>  Adds the specified field to a response header provided that the response code equals 200, 201 (1.3.10), 204, 206, 301, 302, 303, 304, 307 (1.1.16, 1.0.13), or 308 (1.13.0). Parameter value can contain variables.
+>
+>  There could be several `add_header` directives. These directives are inherited from the previous level if and only if there are no `add_header` directives defined on the current level.
+>
+>  如果当前层级没有 add_header 指令,那么会继承上层的配置。
+>
+>  If the `always` parameter is specified (1.7.5), the header field will be added regardless of the response code.
+>
+>  如果add_header指定了 always,无论响应码是多少header都会被添加。
+
+
+
+2种情况:
+
+1. rewrite 不管请求 `/path1` 还是 `/path2`,最终 header 都只有 B
+
+```nginx
+location /path1 {
+    add_header A a;
+    rewrite / /path2;
+}
+
+location /path2 {
+    add_header B b;
+    return 200 "OK";
+}
+```
+
+2. 下面的配置,如果 OPTIONS 类型的请求,那么 responses 的header 只会有 `Access-Control-Max-Age`、`Content-Type`、`Content-Length`,即 if 语句内并不会继承外部的 add_header 设置。
+
+```nginx
+add_header 'Access-Control-Allow-Origin' $http_origin;
+add_header 'Access-Control-Allow-Credentials' 'true';
+add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control';
+add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+if ($request_method = 'OPTIONS') {
+    add_header 'Access-Control-Max-Age' 1728000;
+    add_header 'Content-Type' 'text/plain; charset=utf-8';
+    add_header 'Content-Length' 0;
+    return 204;
+}
+```
+
+
+
+这种解决跨域的配置对 请求头 ContentType: application/json 的 post 请求无效。原因是
+
+*在使用Ajax跨域请求时,如果设置Header的ContentType为application/json,会分两次发送请求。第一次先发送Method为OPTIONS的请求到服务器,这个请求会询问服务器支持哪些请求方法(GET,POST等),支持哪些请求头等等服务器的支持情况。等到这个请求返回后,如果原来我们准备发送的请求符合服务器的规则,那么才会继续发送第二个请求,否则会在Console中报错。更多信息参考:https://www.cnblogs.com/shamo89/p/7837451.html*
+
+
+
+**综上2个因素,导致请求头 ContentType: application/json 的 post 请求跨域失败的原因是,OPTIONS 请求没有跨域配置。**
+
+简单粗暴的办法:直接将外部的跨域配置复制一份到 OPTIONS 请求中。
+
+```nginx
+add_header 'Access-Control-Allow-Origin' $http_origin;
+add_header 'Access-Control-Allow-Credentials' 'true';
+add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control';
+add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+if ($request_method = 'OPTIONS') {
+    add_header 'Access-Control-Allow-Origin' $http_origin;
+    add_header 'Access-Control-Allow-Credentials' 'true';
+    add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+    add_header 'Access-Control-Allow-Headers' 'Content-Type,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control';
+    add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
+    add_header 'Access-Control-Max-Age' 1728000;
+    add_header 'Content-Type' 'text/plain; charset=utf-8';
+    add_header 'Content-Length' 0;
+    return 204;
+}
+```
+
+> Proxy_pass 说明:
+>
+> location /sys-web {
+> ​	...
+> ​	proxy_pass http://127.0.0.1:8080;  # location 和 proxy_pass有无斜杠 "/" 有很大关系,一定注意!!!
+> ​	...
+> }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+

+ 12 - 0
windows/win11右键菜单还原.md

@@ -0,0 +1,12 @@
+
+看了网上那些一步步操作注册表的教程,差点劝退我这个 CLI 党。来个简单到不是教程的教程吧:  
+  
+右击左下角的徽标,在弹出菜单中选择 Windows 终端(管理员)  
+粘贴如下命令,回车即可完成设置。此操作将强制重启资源管理器! 
+```
+reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f  
+
+taskkill /F /IM explorer.exe  
+
+explorer.exe
+```

+ 2 - 0
中间件/ES基础查询语法.md

@@ -0,0 +1,2 @@
+参考:[ES基础查询语法一览](https://zhuanlan.zhihu.com/p/587374960)
+

+ 310 - 0
中间件/RabiitMQ3.7.24主从环境搭建指南.md

@@ -0,0 +1,310 @@
+* 目标
+
+  消息通知:RabbitMQ 3.7.24 (master-slave)
+
+
+| IP                  | 端口  | 账号  | 密码      |
+| ------------------- | ----- | ----- | --------- |
+| 10.18.226.160(主) | 15672 | admin | jhlrb0715 |
+| 10.18.226.167(从) | 15672 | admin | jhlrb0715 |
+
+访问地址:
+
+http://10.18.226.160:15672/#/
+
+http://10.18.226.167:15672/#/
+
+## RabbitMQ 安装
+
+参考 :
+https://www.cnblogs.com/yingxiaocao/p/13282058.html
+https://www.cnblogs.com/yang-hao/p/11737646.html
+
+### 1. 准备
+```
+yum -y install make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel unixODBC unixODBC-devel httpd python-simplejson
+```
+
+### 2. 安装erlang
+
+因为 rabbitmq 是 erlang 语言开发的,所以安装 rabbitmq 之前要安装 erlang 环境。
+
+根据要安装的 rabbitmq 版本安装对应的 erlang 版本,它们的对应关系参考https://www.rabbitmq.com/which-erlang.html
+
+```
+#1.下载安装包(如果下载太慢的话,可以本地下载完后再上传到服务器)
+wget http://www.erlang.org/download/otp_src_21.3.tar.gz
+
+#2.解压
+tar -zxvf otp_src_21.3.tar.gz -C /usr/local/
+
+#3.进入解压目录
+cd /usr/local/otp_src_21.3/
+
+./configure --prefix=/usr/local/erlang --enable-smp-support --enable-threads --enable-sctp --enable-kernel-poll --enable-hipe --with-ssl --without-javac
+
+#4.编译并安装
+make && make install
+
+#5.配置环境变量
+vim /etc/profile
+`export PATH=$PATH:/usr/local/erlang/bin`
+source /etc/profile
+
+#6.验证,进入erlang开发命令行,输入 halt(). 退出
+erl
+>halt().
+```
+
+### 3. 安装 rabbitMQ
+```
+#1.下载页面 https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.7.24
+wget https://github.com/rabbitmq/rabbitmq-server/releases/download/v3.7.24/rabbitmq-server-generic-unix-3.7.24.tar.xz
+
+#2.解压
+xz -d rabbitmq-server-generic-unix-3.7.24.tar.xz
+tar -xvf rabbitmq-server-generic-unix-3.7.24.tar -C /usr/local/
+
+#4.配置环境变量,方便执行命令
+vim /etc/profile
+`export PATH=$PATH:/usr/local/rabbitmq_server-3.7.24/sbin`
+source /etc/profile
+
+#3.启动
+#启动
+rabbitmq-server -detached
+
+#开启管理插件 
+rabbitmq-plugins enable rabbitmq_management
+#开启 rabbitmq
+rabbitmqctl start_app
+
+#4.添加用户
+#新增用户
+rabbitmqctl add_user admin admin
+#分配角色
+rabbitmqctl set_user_tags admin administrator
+#分配权限
+rabbitmqctl set_permissions -p "/" admin ".*" ".*" ".*"
+#查看用户
+rabbitmqctl list_users
+
+#5.访问http://10.18.226.160:15672
+```
+rabbitMQ 常用命令
+* `rabbitmq-server -detached` 开启rabbitmq服务 
+* rabbitmqctl status 查看服务状态: 
+* rabbitmqctl start_app 开启rabbitmq 
+* rabbitmq-plugins enable rabbitmq_management 开启管理插件 
+* rabbitmq-plugins list 查看插件集合: 
+* http://192.168.200.130:15672  访问可视化界面: 
+* rabbitmqctl stop :停止rabbitmq
+* rabbitmq-server restart : 重启rabbitmq
+
+
+用户管理命令:
+
+* rabbitmqctl list_users 查看所有用户
+* rabbitmqctl add_user admin admin 添加一个用户
+* rabbitmqctl  change_password  Username  'Newpassword' 修改密码
+* rabbitmqctl set_permissions -p "/" zhaobl ".*" ".*" ".*" 配置权限
+* rabbitmqctl list_user_permissions zhaobl 查看用户权限
+* rabbitmqctl set_user_tags zhaobl administrator 设置tag
+* rabbitmqctl delete_user guest 删除用户(安全起见,删除默认用户)
+
+
+> 注意:端口 15672 需要对外开放。
+> 当不知道端口15672是否开放时,尝试
+> 1)cur http://localhost:15672 ,如果有内容,证明可视化界面是开启了的
+> 2)将 80 端口的请求转发给 15672(因为一般80端口都是开放的),在外部访问 http://10.18.226.160 ,看是否出现可视化界面。出现说明15672在外部无法访问。
+
+
+
+### 4. 开启启动
+
+
+
+## RabbitMQ 主从配置
+
+参考 
+https://blog.csdn.net/weixin_34290631/article/details/91704046
+
+### 1. 确保节点之间主机名称可以相互解析
+在两台节点服务器上分别配置hosts文件,加入所有的节点主机名称
+```
+vim /etc/hosts
+192.168.10.5 aiot-1-1
+192.168.10.9 aiot-1-2
+```
+注意:配置的主机名不要含有特殊符号,如.\-之类的,如主机名不能为node1.xxx.com
+
+### 2. 同步.erlang.cookie文件
+Rabbitmq的集群是依赖于erlang的集群来工作的,所以必须先构建起erlang的集群环境。Erlang的集群中各节点是通过一个magic cookie来实现的,这个cookie存放在$HOME/.erlang.cookie 中,文件是400的权限。所以必须保证各节点cookie保持一致,否则节点之间就无法通信。
+```
+#1.查看.erlang.cookie文件的权限
+ll ~/.erlang.cookie
+-r-------- 1 root root 20 Dec  7 00:00 /root/.erlang.cookie
+
+#2.将node1中的.erlang.cookie通过scp传输到node1中去
+scp -rp ~/.erlang.cookie root@192.168.10.9:/root
+
+#3.分别在node1和node2查看同步后的.erlang.cookie是否一致
+cat ~/.erlang.cookie
+
+```
+
+### 3.查看集群状态
+```
+#分别查看一下集群状态
+rabbitmqctl cluster_status
+```
+node1:
+```
+[root@aiot-1-1 sbin]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-1 ...
+[{nodes,[{disc,['rabbit@aiot-1-1']}]},
+ {running_nodes,['rabbit@aiot-1-1']},
+ {cluster_name,<<"rabbit@aiot-1-1">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-1',[]}]}]
+
+```
+node2:
+```
+[root@aiot-1-2 ~]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-2 ...
+[{nodes,[{disc,['rabbit@aiot-1-2']}]},
+ {running_nodes,['rabbit@aiot-1-2']},
+ {cluster_name,<<"rabbit@aiot-1-2">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-2',[]}]}]
+ 
+```
+
+### 4. 将node2加入node1节点,创建主从同步
+主机在加入集群之前必须停掉本机的集群服务;
+如node2要加入node1,需要现在node2上执行命令
+```
+#关闭集群服务,然后再执行以下命令加入node1的集群:
+rabbitmqctl stop_app
+
+#加入node1节点,执行此步骤之前确保主节点服务器是开启的:
+rabbitmqctl join_cluster --ram rabbit@aiot-1-1
+#注:--ram指的是作为内存节点,要是想做为磁盘节点的话,就不用加--ram这个参数了,如果磁盘是ssd,建议不加—ram
+#注:执行该命令,一定一定要确认主机是否对外开放了端口 4379 和 25672!!如果没有开放这两个端口的话,会一直提示 unable to connect to epmd (port 4369) timeout (timed out)
+#注:RabbitMQ端口说明 参考https://www.cnblogs.com/liuxingke/articles/9889517.html
+
+#开启rabbitmq
+rabbitmqctl start_app 
+
+```
+
+在node1和node2 中分别执行
+```
+[root@aiot-1-2 ~]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-2 ...
+[{nodes,[{disc,['rabbit@aiot-1-1']},{ram,['rabbit@aiot-1-2']}]},
+ {running_nodes,['rabbit@aiot-1-1','rabbit@aiot-1-2']},
+ {cluster_name,<<"rabbit@aiot-1-1">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-1',[]},{'rabbit@aiot-1-2',[]}]}]
+
+```
+
+### 5. 验证同步
+
+在 node1 上修改用户dmin 的密码
+```
+rabbitmqctl  change_password  admin jhlrb0715
+```
+
+分别访问 http://10.18.226.160:15672 和 http://10.18.226.167:15672 尝试使用 admin 账号密码登录
+
+### *6. 节点退出集群
+如果 node2 要退出集群
+```
+#1.首先关闭节点
+rabbitmqctl stop_app
+
+#2.退出集群
+rabbitmqctl reset
+#如果只剩下最后一个节点,则执行
+rabbitmqctl force_reset
+#注:该命令含义与 rabbitmqctl join_cluster --ram rabbit@aiot-1-1 相反
+
+#3.开启节点
+rabbitmqctl start_app
+
+```
+
+### 7. 关闭其中一个节点,观察另一个节点的集群状态
+
+```
+#关闭node1节点,查看node2的集群状态
+[root@aiot-1-2 ~]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-2 ...
+[{nodes,[{disc,['rabbit@aiot-1-1']},{ram,['rabbit@aiot-1-2']}]},
+ {running_nodes,['rabbit@aiot-1-2']},
+ {cluster_name,<<"rabbit@aiot-1-1">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-2',[]}]}]
+
+```
+注:从节点重启后,会自动连接上集群,不过需要大约15-20秒。(我的测试结果更快)
+
+### *8. 如何将节点中磁盘点修改为内存点:
+
+如,将node1的磁盘点改为内存点
+```
+[root@aiot-1-1 ~]# rabbitmqctl stop_app
+Stopping rabbit application on node rabbit@aiot-1-1 ...
+[root@aiot-1-1 ~]# rabbitmqctl  change_cluster_node_type ram
+Turning rabbit@aiot-1-1 into a ram node
+Error:
+{:resetting_only_disc_node, 'You cannot reset a node when it is the only disc node in a cluster. Please convert another node of the cluster to a disc node first.'}
+```
+**注:节点中必须最少要有一个disc点(磁盘点),这是为了永久化存储考虑**
+
+1)想将node2改为磁盘点
+```
+[root@aiot-1-2 ~]# rabbitmqctl stop_app
+Stopping rabbit application on node rabbit@aiot-1-2 ...
+[root@aiot-1-2 ~]# rabbitmqctl change_cluster_node_type disc
+Turning rabbit@aiot-1-2 into a disc node
+[root@aiot-1-2 ~]# rabbitmqctl start_app
+```
+2)将node1改为内存点
+
+```
+#查看集群状态,可发现 node1 和 node2 都是 磁盘点disc了
+[root@aiot-1-1 ~]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-1 ...
+[{nodes,[{disc,['rabbit@aiot-1-1','rabbit@aiot-1-2']}]},
+ {running_nodes,['rabbit@aiot-1-1']},
+ {cluster_name,<<"rabbit@aiot-1-1">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-1',[]}]}]
+
+#关闭node1
+[root@aiot-1-1 ~]# rabbitmqctl stop_app
+Stopping rabbit application on node rabbit@aiot-1-1 ...
+
+#改为内存点
+[root@aiot-1-1 ~]# rabbitmqctl  change_cluster_node_type ram
+Turning rabbit@aiot-1-1 into a ram node
+
+#开启node1
+[root@aiot-1-1 ~]# rabbitmqctl start_app
+Starting node rabbit@aiot-1-1 ...
+ completed with 3 plugins.
+ 
+#再次查看集群状态,发现node1时内存点,node2依然是磁盘点
+[root@aiot-1-1 ~]# rabbitmqctl cluster_status
+Cluster status of node rabbit@aiot-1-1 ...
+[{nodes,[{disc,['rabbit@aiot-1-2']},{ram,['rabbit@aiot-1-1']}]},
+ {running_nodes,['rabbit@aiot-1-2','rabbit@aiot-1-1']},
+ {cluster_name,<<"rabbit@aiot-1-1">>},
+ {partitions,[]},
+ {alarms,[{'rabbit@aiot-1-2',[]},{'rabbit@aiot-1-1',[]}]}]
+
+```

+ 30 - 0
前端/JS中的位置和宽度:clientWidth、offsetWidth、scrollWidth 等的区别.md

@@ -0,0 +1,30 @@
+## clientWidth和clientHeigh、clientTop和clientLeft
+
+- clientWidth 表示可视区宽度,clientWidth = width + 左右padding
+- clientHeigh 表示可视区高度,clientHeigh = height + 上下padding
+- clientTop 表示实际宽度,clientTop = boder.top(上边框的宽度)
+* clientLeft的实际宽度,clientLeft = boder.left(左边框的宽度)
+
+## offsetWidth和offsetHight、offsetTop和offsetLeft
+    
+* offsetWidth的实际宽度,offsetWidth = width + 左右padding + 左右boder
+* offsetHeith的实际高度,offsetHeith = height + 上下padding + 上下boder
+* offsetTop实际宽度,offsetTop:当前元素 上边框 外边缘 到 最近的已定位父级(offsetParent) 上边框 内边缘的 距离。如果父级都没有定位,则分别是到body 顶部 和左边的距离
+* offsetLeft实际宽度,offsetLeft:当前元素 左边框 外边缘 到 最近的已定位父级(offsetParent) 左边框 内边缘的            距离。如果父级都没有定位,则分别是到body 顶部 和左边的距离
+
+## scrollWidth和scrollHeight 、 scrollTop和scrollLeft
+    
+* scrollWidth实际宽度,scrollWidth:获取指定标签内容层的真实宽度(可视区域宽度+被隐藏区域宽度)。
+* scrollHeight:获取指定标签内容层的真实高度(可视区域高度+被隐藏区域高度)
+* scrollTop :内容层顶部 到 可视区域顶部的距离
+* scrollLeft:内容层左端 到 可视区域左端的距离.
+
+ 实例:var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
+
+ 持续获取高度的方式:
+```js
+window.addEventListener(‘scroll’, ()=>{
+var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
+});
+
+```

+ 35 - 0
前端/JavaScript和Jquery插件开发指南.md

@@ -0,0 +1,35 @@
+参考 [jQuery插件开发精品教程,让你的jQuery提升一个台阶](https://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html)
+
+```js
+// 自调用匿名空间(避免代码命名冲突)  
+;(function(window, document, undefined) {  
+    //定义Beautifier的构造函数  
+    var Beautifier = function(ele, opt) {  
+        this.$element = ele,  
+        this.defaults = {  
+            'color': 'red',  
+            'fontSize': '12px',  
+            'textDecoration': 'none'  
+        },  
+        this.options = $.extend({}, this.defaults, opt)  
+    }  
+    //定义Beautifier的方法  
+    Beautifier.prototype = {  
+        beautify: function() {  
+            return this.$element.css({  
+                'color': this.options.color,  
+                'fontSize': this.options.fontSize,  
+                'textDecoration': this.options.textDecoration  
+            });  
+        }  
+    }  
+    //在插件中使用Beautifier对象  
+    window.myPlugin = function(options) {  
+        //创建Beautifier的实体  
+        var beautifier = new Beautifier(this, options);  
+        //调用其方法  
+        return beautifier.beautify();  
+    }  
+})(jQuery, window, document);
+```
+

+ 72 - 0
前端/css文件超长自动滚动.md

@@ -0,0 +1,72 @@
+当文本内容长度超过容器元素宽度时,要求文本自动滚动,如下图
+
+![](Pasted%20image%2020240425134406.png)
+
+
+有以下两点限制:
+
+- 文本不能全部显示出来,不能超出容器宽度
+- 文本不能自动换行
+
+> 原理:**当子元素的实际内容长度 `scrollWith` 大于可视区宽度 `clientWith` 时,利用 `position:relative` 的属性来对子元素进行左右移动,使子元素的所有内容能够在父元素的可视区宽度内展示出来**
+> 
+> 就相当于我们透过一个小窗口看窗外经过的火车一样,小窗口是父元素,而经过的火车是子元素
+
+_element.clientwidth 表示元素的可视区宽度, element.scrollWidth 表示元素内容宽度_
+
+父元素要设置 `overflow: hidden` ,以便能够隐藏子元素超出内容。但是子元素不能够设置 `overflow: hidden` ,因为子元素设置了该属性,那么子元素的 `clientWidth` 就和 `scrollWidth` 相等了。
+
+下面是源码,复制即可运行。
+
+```html
+<!doctype html>
+<html lang="zh">  
+<head>  
+    <meta charset="UTF-8">  
+    <title>文本过长自动滚动</title>  
+    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>  
+    <style type="text/css">  
+        * {  
+            margin: 0;  
+            padding: 0;  
+        }  
+        #parentEle {  
+			margin: 0 auto;  
+			border: 1px solid blue;  
+			/* 固定宽度 */  
+            width: 100px;  
+			/* 超过宽度自动隐藏 */  
+            overflow: hidden;  
+        }  
+		#sonEle {  
+			/* 相对位置 */  
+			position: relative;  
+			/* 不能自动换行 */  
+			white-space: nowrap;  
+		}  
+    </style>  
+</head>  
+<body>  
+    <div id="parentEle">  
+        <div id="sonEle">  
+            春草带雨晚来急,野渡无人舟自横  
+        </div>  
+    </div>  
+    <script>  
+    	$(function(){  
+            var sonEle = document.querySelector("#sonEle");  
+			// 子元素实际内容长度超过可视区宽度  
+            if (sonEle.scrollWidth > sonEle.clientWidth) {  
+                var d = sonEle.scrollWidth - sonEle.clientWidth;  
+				$(sonEle).animate({left: -d +'px'}, 3000);  
+                $(sonEle).animate({left:'0px'}, 3000);  
+                setInterval(function(){  
+                    $(sonEle).animate({left: -d +'px'}, 3000);  
+                    $(sonEle).animate({left:'0px'}, 3000);  
+                }, 6000);  
+            }  
+        })  
+    </script>  
+</body>  
+</html>
+```

BIN
前端/imgs/Pasted image 20240425134406.png


+ 183 - 0
前端/js基础语法.md

@@ -0,0 +1,183 @@
+## 数组 Array
+### 定义
+```js
+let arr1 = ["周一", "周二", "周三"];
+let arr2 = new Array("2019年", "2020年", "2021年");
+```
+
+### 属性
+Array 具有 length 属性,即可获取也可设置。
+```js
+// 获取数据长度
+var arrayLength = arr.length;
+// 设置数组长度(超出数组长度的元素将被抛弃)
+arr.length = 2;
+```
+
+### 方法
+
+pop(); // 取出并删除数组最后一个元素
+
+push(element); // 在数组末尾追加元素
+
+shifit(); // 取出并删除数组第一个元素
+
+unshift(element); // 在数组开头添加元素
+
+indexOf(element); // 查找元素的第一个位置
+
+lastIndexOf(element); // 查找元素的最后一个位置
+
+splice(start, length, [e1, ...]); // 从start位置开始删除length个元素,并插入后面的参数元素(相当于替换)
+
+```js
+var arr1 = [2, 4, 6];
+arr1.splice(1, 2, 1, 3, 5);
+console.log(arr1);	// 输出 '[2, 1, 3, 5]'
+join(char); // 数组元素以字符相连接,并返回字符串
+
+sort([fn]); // 默认把元素看做字符串自然排序,也可传入函数自定义排序
+
+var arr2 = [3, 5, 2, 9];
+arr2.sort(function(n1, n2) {
+	return n1 - n2;	// 前者大于后者,升序排列
+});
+console.log(arr2);	// 输出 '[2, 3, 5, 9]'
+遍历
+var arr = ['冰箱', '电视', '手机'];
+// 第1种遍历
+for (var i=0; i<arr.length; i++) {
+    console.log(i, arr[i]);
+}
+
+// 第2种遍历
+arr.forEach(function(item, index, array){
+    console.log(index, item);
+})
+```
+
+## 对象 Object
+
+## 函数 function
+一个函数应该只返回一种类型的值。
+
+函数中有一个默认的数组变量arguments,存储着传入函数的所有参数。为了使用函数参数方便,建议给参数起个名字。
+
+```js
+function fun1(obj, name, value){
+    console.log(arguments);
+    console.log(obj);
+    console.log(name);
+    console.log(value);
+}
+fun1({'id':12}, 'username', '张三');
+```
+
+
+## 日期 Date
+### 定义
+```js
+var date1 = new Date();
+var date2 = new Date(timestamp);	// timestamp 毫秒单位的时间戳
+var date3 = new Date(year, month-1, dayOfMonth, hour, minute, second);
+```
+
+### 方法
+
+getFullYear();  //获取年份
+getMonth();    //获取月份,月份从0开始,即0表示1月,1表示2月,以此类推
+getDate();    //获取当前月份的第几日
+getHours();   //时
+getMinutes();  //分
+getSeconds();  //秒
+getTime(); // 毫米级时间戳
+
+### 扩展
+```js
+/**
+ * 扩展Date对象的功能
+ * @param format
+ * @returns
+ * @example  (new Date()).format('yyyy-MM-dd hh:mm:ss')    结果是 2018-08-13 08:42:34 这样的格式 ;
+ */
+Date.prototype.format = function (format) {
+    var o = {
+        "M+": this.getMonth() + 1, // month
+        "d+": this.getDate(), // day
+        "h+": this.getHours(), // hour
+        "m+": this.getMinutes(), // minute
+        "s+": this.getSeconds(), // second
+        "q+": Math.floor((this.getMonth() + 3) / 3), // quarter
+        "S": this.getMilliseconds()
+        // millisecond
+    }
+    if (/(y+)/.test(format)) {
+        format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+    }
+    for (var k in o) {
+        if (new RegExp("(" + k + ")").test(format)) {
+            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
+        }
+    }
+    return format;
+}
+
+/**
+ * 扩展Date对象的功能
+ * 获取上一个月日期对象
+ * @param date
+ * @returns {Date}
+ */
+Date.prototype.getPreMonth = function() {
+    var year = this.getFullYear();
+    var month = this.getMonth()+1;
+    var day = this.getDate();
+    var hour = this.getHours();
+    var minute = this.getMinutes();
+    var second = this.getSeconds();
+    
+    var y = year;
+    var m = parseInt(month) - 1;
+    if (m == 0) {    // 如果是一月
+        y = parseInt(y) - 1;
+        m = 12;
+    }
+    
+    var monthDays = new Date(y, m, 0).getDate(); //获取 m 月的天数
+    var d = day;
+    if (d > monthDays) {
+        d = monthDays;
+    }
+    return new Date(y, m-1, d, hour, minute, second);
+}
+
+
+/**
+ * 扩展Date对象的功能
+ * 获取下一个月的日期
+ * @param date
+ * @returns {Date}
+ */
+Date.prototype.getNextMonth = function(){
+    var year = date.getFullYear();
+    var month = date.getMonth()+1;
+    var day = date.getDate();
+    var hour = date.getHours();
+    var minute = date.getMinutes();
+    var second = date.getSeconds();
+    
+    var y = year;
+    var m = parseInt(month) + 1;
+    if (m == 13) {
+        y = parseInt(y) + 1;
+        m = 1;
+    }
+    
+    var d = day;
+    var monthDays = new Date(y, m, 0).getDate(); // 获取 m 月的天数
+    if (d > monthDays) {
+        d = monthDays;
+    }
+    return new Date(y, m-1, d, hour, minute, second);
+}
+```

+ 24 - 0
前端/js常用函数.md

@@ -0,0 +1,24 @@
+
+## 解析URL参数为json
+```javascript
+
+/**
+ * 解析URL参数为json对象
+ * 
+ * @param url
+ * @return json
+ */
+function parseUrlParams(url) {
+	url = url || 'http://qq.com/s?a=b#rd';   
+	var tmp = url.split('?'),  
+		paramStr = (tmp[1] || "").split('#')[0],  
+		query = paramStr ? paramStr.split('&') : [],  
+		params = {};  
+	for (var i=0; i<query.length; i++) {  
+		var arg = query[i].split('=');  
+		params[arg[0]] = arg[1];  
+	}  
+	return params;
+}
+```
+

+ 0 - 2
前端/nodejs.md

@@ -1,2 +0,0 @@
-1. 下载安装包并安装,官网地址:https://nodejs.org/en
-2. 打开CMD,输入 node -v 验证是否安装成功

+ 159 - 0
前端/鼠标滚轮滚动翻页.md

@@ -0,0 +1,159 @@
+参考自 [JS滚轮事件(mousewheel/DOMMouseScroll)了解](https://www.zhangxinxu.com/wordpress/2013/04/js-mousewheel-dommousescroll-event/)  
+页面代码改造自 [原生JS实现全屏滚动(无滚动条)](https://blog.csdn.net/qq_40756247/article/details/86138474)
+
+```html
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<title></title>
+		<style type="text/css">
+			* {
+				margin: 0;
+				padding: 0;
+				font-size: 0;
+			}
+			.box {
+				position: relative;
+				width: 100%;
+				height: 100vh;
+				overflow: hidden;
+			}
+			ul {
+				position: relative;
+			}
+			li {
+				width: 100%;
+				height: 100vh;
+				font-size: 30px;
+				position: relative;
+				display: flex;
+				justify-content: center;
+				text-align: center;
+			}
+			
+			.nav {
+				position: fixed;
+				right: 2%;
+				top: 35%;
+			}
+			.nav li {
+				width: 16px;
+				height: 16px;
+				border-radius: 50%;
+				border: 1.5px solid #000;
+				margin-bottom: 5px;
+			}
+		</style>
+	</head>
+	<body>
+		<div class="box">
+			<ul style="transition: 0.5s ease; top:0;">
+				<li>一页面</li>
+				<li>二页面</li>
+				<li>三页面</li>
+				<li>四页面</li>
+			</ul>
+		</div>
+		<div class="nav">
+			<ul>
+				<li></li>
+				<li></li>
+				<li></li>
+				<li></li>
+			</ul>
+		</div>
+		<script type="text/javascript">
+			/**
+			 * 简易的事件添加方法封装
+			 */
+			var addEvent = (function(window, undefined) {
+				var _eventCompat = function(event) {
+					var type = event.type;
+					if (type == 'DOMMouseScroll' || type == 'mousewheel') {
+						event.delta = (event.wheelDelta) ? event.wheelDelta / 120 : -(event.detail || 0) / 3;
+					}
+					//alert(event.delta);
+					if (event.srcElement && !event.target) {
+						event.target = event.srcElement;
+					}
+					if (!event.preventDefault && event.returnValue !== undefined) {
+						event.preventDefault = function() {
+							event.returnValue = false;
+						};
+					}
+					/*
+					   ......其他一些兼容性处理 */
+					return event;
+				};
+				if (window.addEventListener) {
+					return function(el, type, fn, capture) {
+						if (type === "mousewheel" && document.mozFullScreen !== undefined) {
+							type = "DOMMouseScroll";
+						}
+						el.addEventListener(type, function(event) {
+							fn.call(this, _eventCompat(event));
+						}, capture || false);
+					}
+				} else if (window.attachEvent) {
+					return function(el, type, fn, capture) {
+						el.attachEvent("on" + type, function(event) {
+							event = event || window.event;
+							fn.call(el, _eventCompat(event));
+						});
+					}
+				}
+				return function() {};
+			})(window);
+
+			// 滚动锁
+			var mousewheelLock = false;
+			var pageIndex = 0,	// 页码
+				pageNum = 4;	// 页数
+			// 滚动动画时间	
+			var scrollAnimateTime = 1200;
+				
+			var oUl = document.querySelector("ul");
+			var navLis = document.querySelectorAll(".nav li");
+			navLis[pageIndex].style.background = 'black';
+			
+			/** 添加鼠标滚轮事件 **/
+			addEvent(oUl, 'mousewheel', function(event) {
+				if (mousewheelLock) return ;
+                mousewheelLock = true;
+                // 向下滚动
+                if (event.delta < 0) {
+                    nextPage();
+                } else {	// 向上滚动
+                    prevPage();
+                }
+                setTimeout(function(){
+                    mousewheelLock = false;
+                }, scrollAnimateTime);
+			});
+			// 下一页
+			function nextPage() {
+				if (pageIndex < pageNum-1 ) {
+					changePage(pageIndex++);
+				}
+			}
+			// 上一页
+			function prevPage() {
+				if (pageIndex > 0 ) {
+					changePage(pageIndex--);
+				}
+			}
+            // 改变页面
+			function changePage(selectedPageIndex) { 
+				oUl.style.top = -selectedPageIndex * 100 + 'vh';
+				for (var i=0; i<navLis.length; i++) {
+					navLis[i].style.background = 'white';
+				}
+				navLis[pageIndex].style.background = 'black';
+			}
+
+		</script>
+	</body>
+</html>
+
+```