<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>陌行者笔记</title><description>编程教程/开源项目/开发工具一站式下载</description><link>https://www.motouguai.com/</link><language>zh_CN</language><item><title>linux centos 磁盘异常占用满了排查和解决</title><link>https://www.motouguai.com/posts/linux-centos-ci-pan-yi-chang-zhan-yong-man-liao-pai-cha-he-jie-jue-zld0xz/</link><guid isPermaLink="true">https://www.motouguai.com/posts/linux-centos-ci-pan-yi-chang-zhan-yong-man-liao-pai-cha-he-jie-jue-zld0xz/</guid><pubDate>Mon, 03 Mar 2025 07:39:50 GMT</pubDate><content:encoded>&lt;h1&gt;linux centos 磁盘异常占用满了排查和解决&lt;/h1&gt;
&lt;h3&gt;4. &lt;strong&gt;使用交互式工具&lt;/strong&gt;​&lt;strong&gt;​&lt;code&gt;ncdu&lt;/code&gt;​&lt;/strong&gt;​ &lt;strong&gt;（推荐）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;安装后扫描更直观（支持排除&lt;code&gt;/home&lt;/code&gt;）：&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install ncdu  # Debian/Ubuntusudo yum install ncdu  # CentOS/RHEL
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;扫描命令：&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo ncdu --exclude /home /
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;操作方式&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;方向键导航，&lt;code&gt;Enter&lt;/code&gt;进入子目录。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;d&lt;/code&gt;​删除文件（谨慎使用），&lt;code&gt;g&lt;/code&gt;显示大小百分比。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;系统层&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;首先查看磁盘使用情况：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看磁盘分区使用情况
df -h

# 查看具体目录大小
du -sh /*
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查找大文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查找大于100M的文件
find / -type f -size +100M -exec ls -lh {} \;

# 按大小排序显示前10个最大的文件
find / -type f -exec du -Sh {} + | sort -rh | head -n 10
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查日志文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看/var/log目录大小
du -sh /var/log/*

# 清理旧日志
sudo find /var/log -type f -name &quot;*.log.*&quot; -delete
sudo find /var/log -type f -name &quot;*.gz&quot; -delete

# 清空大日志文件（不删除文件本身）
sudo truncate -s 0 /var/log/large_log_file.log
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理软件包缓存：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 清理yum缓存
sudo yum clean all

# 删除旧的软件包
sudo package-cleanup --oldkernels --count=2
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查并清理临时文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看/tmp目录大小
du -sh /tmp

# 清理临时文件
sudo rm -rf /tmp/*
sudo rm -rf /var/tmp/*
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查Docker（如果安装了）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看Docker使用空间
docker system df

# 清理未使用的Docker资源
docker system prune -a

# 清理Docker日志
sudo sh -c &apos;truncate -s 0 /var/lib/docker/containers/*/*-json.log&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查用户目录：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看home目录下各用户空间占用
du -sh /home/*

# 查找用户目录下的大文件
find /home -type f -size +100M -exec ls -lh {} \;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理系统旧文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 清理旧的core文件
find / -name core -type f -delete

# 清理0字节文件
find / -size 0 -type f -delete
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查并清理邮件队列（如果有邮件服务）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看邮件队列目录大小
du -sh /var/spool/mail/
du -sh /var/spool/postfix/
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;检查数据库文件（如果有）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# MySQL数据目录
du -sh /var/lib/mysql/*

# PostgreSQL数据目录
du -sh /var/lib/pgsql/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;清理后：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 再次检查磁盘使用情况
df -h

# 如果还需要进一步分析
ncdu -x /
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;docker层&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;首先查看 Docker 系统占用情况：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查看 Docker 磁盘使用详情
docker system df -v

# 查看具体目录占用
du -sh /var/lib/docker/*
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理未使用的 Docker 资源：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 清理所有未使用的容器、网络、镜像（包括未被任何容器使用的镜像）和构建缓存
docker system prune -a --volumes

# 仅清理悬空镜像（dangling images）
docker image prune

# 清理未使用的数据卷
docker volume prune

# 清理未使用的网络
docker network prune
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理 Docker 日志文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查找大的日志文件
find /var/lib/docker/containers/ -type f -name &quot;*.log&quot; -exec ls -lh {} \;

# 清空所有容器的日志文件
sudo sh -c &apos;truncate -s 0 /var/lib/docker/containers/*/*-json.log&apos;

# 或者使用循环清理
for i in $(docker ps -q); do echo &quot;Cleaning logs for $i...&quot;; truncate -s 0 $(docker inspect --format=&apos;{{.LogPath}}&apos; $i); done
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;限制容器日志大小：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 修改 Docker 守护进程配置
sudo vim /etc/docker/daemon.json

# 添加以下内容
{
  &quot;log-driver&quot;: &quot;json-file&quot;,
  &quot;log-opts&quot;: {
    &quot;max-size&quot;: &quot;10m&quot;,
    &quot;max-file&quot;: &quot;3&quot;
  }
}

# 重启 Docker 服务
sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;删除指定时间之前的资源：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 删除24小时前已停止的容器
docker container prune --filter &quot;until=24h&quot;

# 删除24小时前的镜像
docker image prune -a --filter &quot;until=24h&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;手动删除特定资源：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 停止所有运行的容器
docker stop $(docker ps -aq)

# 删除所有已停止的容器
docker rm $(docker ps -aq -f status=exited)

# 删除所有未使用的镜像
docker rmi $(docker images -q -f dangling=true)
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;清理构建缓存：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 清理构建缓存
docker builder prune -a

# 或者指定时间
docker builder prune --filter until=24h
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;查看并删除大文件：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 查找 Docker 目录下的大文件
find /var/lib/docker -type f -size +100M -exec ls -lh {} \;

# 检查overlay2目录（通常占用最大）
du -sh /var/lib/docker/overlay2/*
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;迁移 Docker 根目录（如果根分区空间不足）：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 停止 Docker 服务
sudo systemctl stop docker

# 创建新目录
sudo mkdir /data/docker

# 编辑 Docker 配置
sudo vim /etc/docker/daemon.json
{
  &quot;data-root&quot;: &quot;/data/docker&quot;
}

# 复制现有 Docker 目录
sudo rsync -avz /var/lib/docker/ /data/docker

# 重启 Docker 服务
sudo systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;设置自动清理：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;# 创建定时清理脚本
cat &amp;gt; /etc/cron.daily/docker-cleanup &amp;lt;&amp;lt; &apos;EOF&apos;
#!/bin/bash
docker system prune -af --volumes
find /var/lib/docker/containers/ -type f -name &quot;*.log&quot; -exec truncate -s 0 {} \;
EOF

# 添加执行权限
chmod +x /etc/cron.daily/docker-cleanup
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>RAG知识库应用在ERP的落地</title><link>https://www.motouguai.com/posts/ragzhi-shi-ku-ying-yong-zai-erpde-luo-di-2wnmjd/</link><guid isPermaLink="true">https://www.motouguai.com/posts/ragzhi-shi-ku-ying-yong-zai-erpde-luo-di-2wnmjd/</guid><pubDate>Mon, 10 Feb 2025 01:28:42 GMT</pubDate><content:encoded>&lt;h1&gt;RAG知识库应用在ERP的落地&lt;/h1&gt;
&lt;p&gt;一些功能的落地场景&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/_astro/rag.DPV4kfmx_Z2hJqNW.webp&quot; alt=&quot;rag思维导图&quot; /&gt;&lt;img src=&quot;https://www.motouguai.com/_astro/2.D9WqsTCS_ZvjwN2.webp&quot; alt=&quot;思维导图2&quot; /&gt;&lt;/p&gt;
</content:encoded></item><item><title>JDK12手动编译</title><link>https://www.motouguai.com/posts/jdk12-manual-compilation-zqbjug/</link><guid isPermaLink="true">https://www.motouguai.com/posts/jdk12-manual-compilation-zqbjug/</guid><pubDate>Fri, 03 Jan 2025 05:19:29 GMT</pubDate><content:encoded>&lt;h1&gt;JDK12手动编译&lt;/h1&gt;
&lt;p&gt;参考文章:&lt;br /&gt;
&lt;a href=&quot;https://juejin.cn/post/7051136295245971464&quot;&gt;https://juejin.cn/post/7051136295245971464&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我使用的是ubuntu22.04的WSL2子系统&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;p&gt;碰到CMAKE的坑&lt;/p&gt;
&lt;p&gt;各种报错解决:&lt;br /&gt;
&lt;a href=&quot;https://juejin.cn/post/7264503091121979407&quot;&gt;https://juejin.cn/post/7264503091121979407&lt;/a&gt;&lt;br /&gt;
https://blog.csdn.net/qq_29734297/article/details/134039834&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/2301_78101515/article/details/130791286&quot;&gt;https://blog.csdn.net/2301_78101515/article/details/130791286&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;https://www.dariawan.com/tutorials/java/build-openjdk-12-fedora-29/&lt;/p&gt;
&lt;p&gt;https://blog.csdn.net/w57685321/article/details/106326558&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;p&gt;bash configure --enable-ccache --disable-warnings-as-errors --enable-debug --with-jvm-variants=server&lt;/p&gt;
&lt;p&gt;https://blog.csdn.net/kq1983/article/details/120805686&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;p&gt;编译后clion调试&lt;/p&gt;
&lt;p&gt;https://blog.csdn.net/zixiao_love/article/details/129038800&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;https://www.jianshu.com/p/0fc877be4c3d&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>jdk1.8升级,jdk21还是jdk17?</title><link>https://www.motouguai.com/posts/upgrade-to-jdk18-jdk21-or-jdk17-1kykcu/</link><guid isPermaLink="true">https://www.motouguai.com/posts/upgrade-to-jdk18-jdk21-or-jdk17-1kykcu/</guid><description>梳理 Java 8 应用升级到 Java 17 或 21 时需要关注的 Spring Boot 3、Jakarta EE、依赖兼容性和构建配置变化。</description><pubDate>Tue, 15 Oct 2024 01:00:29 GMT</pubDate><content:encoded>&lt;h1&gt;jdk1.8升级,jdk21还是jdk17?&lt;/h1&gt;
&lt;p&gt;Spring Boot 3.x 至少需要 Java 17。它不支持 Java 8.&lt;/p&gt;
&lt;p&gt;springboot3和2的组件对比:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Spring Boot 3.x 相较于 Spring Boot 2.x 带来了一系列重要的更新和改进，这些变化旨在提高性能、增强功能、并确保与最新 Java 版本的兼容性。以下是 Spring Boot 3.x 与 Spring Boot 2.x 之间的一些主要区别和新特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Java 版本要求&lt;br /&gt;
Spring Boot 3.x 要求至少使用 Java 17，这是最低版本要求。同时，Spring Boot 3.x 也已经通过了 Java 19 的测试，确保了更好的兼容性和性能。这意味着开发者需要使用 Java 17 或更高版本来运行和开发基于 Spring Boot 3.x 的应用程序。&lt;/li&gt;
&lt;li&gt;Spring Framework 版本&lt;br /&gt;
Spring Boot 3.x 基于最新的 Spring Framework 6 构建，提供了更好的性能和功能。这是对之前 Spring Boot 2.x 使用的 Spring Framework 5.x 的一个重大升级。&lt;/li&gt;
&lt;li&gt;GraalVM 支持和原生镜像&lt;br /&gt;
Spring Boot 3.x 引入了对 GraalVM 的支持，允许开发者使用 GraalVM 将 Spring 应用程序编译成本地可执行的镜像文件。这可以显著提升应用程序的启动速度、峰值性能以及减少内存使用。这一特性取代了之前的 Spring Native 项目。&lt;/li&gt;
&lt;li&gt;Jakarta EE API&lt;br /&gt;
由于 Java EE 已经变更为 Jakarta EE，Spring Boot 3.x 支持 Jakarta EE 10，并且所有的 Java EE 依赖项都已经迁移到了 Jakarta EE API。这要求开发者在使用这些依赖项时，需要相应地更新包名从 javax 开头变更为 jakarta。&lt;/li&gt;
&lt;li&gt;配置属性兼容性&lt;br /&gt;
在 Spring Boot 3.x 中，一些配置属性被重新命名或删除，开发人员需要更新 application.properties 或 application.yml 配置文件。为了帮助开发者进行升级，Spring Boot 提供了 spring-boot-properties-migrator 模块，该模块可以在启动时分析应用程序的环境并打印诊断结果，同时在运行时为开发者临时迁移属性。&lt;/li&gt;
&lt;li&gt;应用可观察性提高&lt;br /&gt;
Spring Boot 3.x 通过 Micrometer 和 Micrometer 追踪提高应用可观察性。新版本支持 Micrometer 1.10 中引入的新的 Observation API，并自动配置 Micrometer 追踪，包括对 Brave、OpenTelemetry、Zipkin 和 Wavefront 组件的支持。&lt;/li&gt;
&lt;li&gt;性能优化&lt;br /&gt;
Spring Boot 3.x 对性能进行了优化，包括启动时间的改进、内存占用的减少以及并发性能的提升。这些优化使得 Spring Boot 3.x 在生产环境中能够更好地满足高性能和高可扩展性的需求。&lt;/li&gt;
&lt;li&gt;其他新特性和改进&lt;br /&gt;
响应式编程支持：Spring Boot 3.x 更加注重响应式编程范式，提供了更多与响应式相关的功能和支持。&lt;br /&gt;
云原生支持：改进了对云原生应用程序开发的支持，提供更多的云服务集成和部署选项，如 Kubernetes、Docker 等。&lt;br /&gt;
开发工具改进：提供了更好的开发工具集成和开发体验，包括更快的启动时间、改进的调试支持等。&lt;br /&gt;
总结&lt;br /&gt;
​&lt;img src=&quot;https://www.motouguai.com/images/image-20241015090732-xqepkim.png&quot; alt=&quot;image&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;JDK版本&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;strong&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk8/&quot;&gt;8&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;03/2014&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;拉姆达斯&lt;/td&gt;
&lt;td&gt;先前发布模型下的最后一个 LTS 版本。Oracle 的免费更新&lt;a href=&quot;https://www.oracle.com/java/technologies/java-se-support-roadmap.html&quot;&gt;结束&lt;/a&gt;，但仍由其他人维护。在接下来的几个月内升级到 11 或 17！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk9/&quot;&gt;9&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;09/2017&lt;/td&gt;
&lt;td&gt;模块&lt;/td&gt;
&lt;td&gt;引入了新的发布模型。停产。立即升级至 17 或 21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/10/&quot;&gt;10&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2018&lt;/td&gt;
&lt;td&gt;变量&lt;/td&gt;
&lt;td&gt;停产。立即升级至 17 或 21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/11/&quot;&gt;11&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;09/2018&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;新的 HTTP 客户端&lt;/td&gt;
&lt;td&gt;立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/12/&quot;&gt;12&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2019&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/13/&quot;&gt;13&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;09/2019&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/14/&quot;&gt;14&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2020&lt;/td&gt;
&lt;td&gt;切换表达式&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/15/&quot;&gt;15&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;09/2020&lt;/td&gt;
&lt;td&gt;文本块&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/16/&quot;&gt;16&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2021&lt;/td&gt;
&lt;td&gt;记录&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/17/&quot;&gt;17 号&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;09/2021&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;密封课程&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;支持 LTS 版本。&lt;/strong&gt;  考虑在接下来的几个月内升级到 21。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/18/&quot;&gt;18&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2022&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/jeps/400&quot;&gt;默认 UTF-8&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/19/&quot;&gt;19&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;09/2022&lt;/td&gt;
&lt;td&gt;仅预览和孵化器功能&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/20/&quot;&gt;20&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Feature&lt;/td&gt;
&lt;td&gt;03/2023&lt;/td&gt;
&lt;td&gt;仅预览和孵化器功能&lt;/td&gt;
&lt;td&gt;停产。立即升级至21！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;a href=&quot;https://openjdk.java.net/projects/jdk/21/&quot;&gt;21&lt;/a&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;LTS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;09/2023&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://wscp.dev/posts/tech/java-pattern-matching/&quot;&gt;模式匹配&lt;/a&gt;,虚拟线程&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;当前的 LTS 版本。&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;a href=&quot;https://openjdk.org/projects/jdk/21/&quot;&gt;OpenJDK 21&lt;/a&gt; 已经发布半年有余，在这个版本中， &lt;a href=&quot;https://openjdk.org/jeps/439&quot;&gt;Generational ZGC&lt;/a&gt; 也一起发布了。在 &lt;a href=&quot;https://malloc.se/blog/zgc-jdk16&quot;&gt;ZGC | What’s new in JDK 16&lt;/a&gt; 中， &lt;a href=&quot;https://malloc.se/&quot;&gt;Per Lidén&lt;/a&gt; 宣称，将 ZGC 的最大停顿时间从 10ms 降低到了 1ms。再加上 &lt;a href=&quot;https://www.diguage.com/post/gc-performance-incremental-qps/&quot;&gt;JVM GC 性能测试（二）：递增流量&lt;/a&gt; 和 &lt;a href=&quot;https://www.diguage.com/post/gc-performance-real-qps/&quot;&gt;JVM GC 性能测试（三）：真实流量&lt;/a&gt; 文中，GenZGC 的惊艳表现，这些种种先进技术，着实充满诱惑，忍不住想吃口螃蟹 🦀。这篇文章，D瓜哥就来分享一下，自己在升级 OpenJDK 21 中的一些经验。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;本文仅介绍升级 OpenJDK 的相关内容，ZGC 原理等会专门撰文介绍。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;h2&gt;升级依赖&lt;/h2&gt;
&lt;p&gt;依赖升级不是 KPI，也不涉及需求交付。所以，大多数项目的依赖自从项目创建后，就很少升级。如果想比较顺利地将项目升级到 OpenJDK 21，那么，先将项目所用依赖做一个整体升级是一个事半功倍的操作。可以直接使用 Maven 命令来检查依赖可以升级的情况：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn versions:display-dependency-updates
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;执行该命令后，会有如下类似输出：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# 检查依赖升级情况
$ mvn versions:display-dependency-updates

# 此处省略一万个字
# @author: D瓜哥 · https://www.diguage.com

[INFO]   org.springframework:spring-aop ......... 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-aspects ..... 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-beans ....... 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-context ..... 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-core ........ 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-jdbc ........ 5.3.33 -&amp;gt; 6.1.6
[INFO]   org.springframework:spring-web ......... 5.3.33 -&amp;gt; 6.1.6

[INFO]   org.mybatis:mybatis-2-spring ............ 1.1.0 -&amp;gt; 1.2.0
[INFO]   org.mybatis:mybatis-spring .............. 2.1.1 -&amp;gt; 2.1.2

[INFO]   org.junit.jupiter:junit-jupiter ........ 5.9.3 -&amp;gt; 5.10.2
[INFO]   org.junit.jupiter:junit-jupiter-api .... 5.9.3 -&amp;gt; 5.10.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可以根据这个输出情况，将相关依赖做一个整体升级。这里再注重提醒三个方面。&lt;/p&gt;
&lt;h3&gt;Lombok&lt;/h3&gt;
&lt;p&gt;如果项目使用了 Lombok 依赖，务必将其升级到 v1.18.30+，低于此版本的 Lombok 会报错，具体原因见： &lt;a href=&quot;https://github.com/projectlombok/lombok/issues/3393&quot;&gt;[BUG] lombok 1.8.26 incompatible with JDK21 · #3393&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;Netty&lt;/h3&gt;
&lt;p&gt;如果项目使用了 Netty，建议进来将其升级到 4.1.93.Final+。OpenJDK 21 对 &lt;code&gt;DirectByteBuffer&lt;/code&gt;​ 的构造函数做了改动，该版本做了兼容。修改日志见： &lt;a href=&quot;https://netty.io/news/2023/05/25/4-1-93-Final.html&quot;&gt;Netty.news: Netty 4.1.93.Final released&lt;/a&gt;，代码改动详情见： &lt;a href=&quot;https://github.com/netty/netty/pull/13366&quot;&gt;Adapt to DirectByteBuffer constructor in Java 21 #13366&lt;/a&gt;。&lt;/p&gt;
&lt;h3&gt;反向兼容 JDK 8&lt;/h3&gt;
&lt;p&gt;另外，提醒一下，如果开发环境还是以 JDK 8 为主，那么 Spring 最好就不要升级到 6.x，能不能忽略类似的相关问题呢？解决办法请参考： &lt;a href=&quot;https://www.diguage.com/post/intro-to-versions-maven-plugin/&quot;&gt;Versions Maven 插件简介&lt;/a&gt;，文章里对忽略版本，一键升级等操作，都做了比较详细的介绍。&lt;/p&gt;
&lt;h2&gt;&lt;code&gt;@javax.annotation.Resource&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;直接将本地使用的 JDK 版本切换成 JDK 21 后，编译大概率会报错，提示找不到 &lt;code&gt;javax.annotation.Resource&lt;/code&gt;​，这是由于 &lt;a href=&quot;https://openjdk.org/jeps/320&quot;&gt;JEP 320: Remove the Java EE and CORBA Modules&lt;/a&gt; 提案，在 OpenJDK 11 中移除了 JavaEE 的相关内容。所以，需要将其使用 Jar 包的形式专门引用一下。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;jakarta.annotation&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jakarta.annotation-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.3.5&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;

&amp;lt;!-- 或者 --&amp;gt;
&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&amp;gt;

&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;javax.annotation&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javax.annotation-api&amp;lt;/artifactId&amp;gt; 
    &amp;lt;version&amp;gt;1.3.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;上述两个依赖代码基本一样。推荐使用该版本，不耽误以后同时使用更高版本的 &lt;code&gt;jakarta.annotation:jakarta.annotation-api&lt;/code&gt;。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;h3&gt;Spring 6+ 同时支持新旧版的 &lt;code&gt;@Resource&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;另外，有一点需要特别说明：Spring 6+ 支持新版的 &lt;code&gt;jakarta.annotation.Resource&lt;/code&gt;​ 注解，同时还兼容旧版的 &lt;code&gt;javax.annotation.Resource&lt;/code&gt;。相关代码如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;有些文章提到，Spring 6 不支持 &lt;code&gt;javax.annotation.Resource&lt;/code&gt; 注解，从下面的 Spring 代码来看，这是完全错误的。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;点击查看 Spring 源码&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Nashorn JavaScript Engine&lt;/h2&gt;
&lt;p&gt;解决完编译问题后，启动报如下异常：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2024-01-02 14:27:27.062 [main] ERROR com.diguage.laf.config.spring.config.JavaScriptListener[67] - failed invoking script script/logback.js
java.lang.NullPointerException: Cannot invoke &quot;javax.script.ScriptEngine.put(String, Object)&quot; because &quot;engine&quot; is null
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是因为 &lt;a href=&quot;https://openjdk.org/jeps/372&quot;&gt;JEP 372: Remove the Nashorn JavaScript Engine&lt;/a&gt; 提案，从 OpenJDK 11 开始，将 Nashorn JavaScript Engine 移除了。由于相关功能使用了 JavaScript 引擎，所以，就报了 “Cannot invoke &quot;javax.script.ScriptEngine.put(String, Object)&quot; because &quot;engine&quot; is null” 错误。处理办法如上，加回相关的依赖：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.openjdk.nashorn&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;nashorn-core&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;15.4&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Java Validation API&lt;/h2&gt;
&lt;p&gt;最近，对一个项目升级中，遇到了如下一个报错：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Caused by: java.lang.ExceptionInInitializerError: Exception javax.validation.ValidationException: HV000183: Unable to initialize &apos;javax.el.ExpressionFactory&apos;. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead [in thread &quot;BZ-22001-108-T-17&quot;]
    at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.buildExpressionFactory(ResourceBundleMessageInterpolator.java:199)
    at org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.&amp;lt;init&amp;gt;(ResourceBundleMessageInterpolator.java:94)
    at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolator(AbstractConfigurationImpl.java:570)
    at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getDefaultMessageInterpolatorConfiguredWithClassLoader(AbstractConfigurationImpl.java:790)
    at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.getMessageInterpolator(AbstractConfigurationImpl.java:480)
    at org.hibernate.validator.internal.engine.ValidatorFactoryImpl.&amp;lt;init&amp;gt;(ValidatorFactoryImpl.java:151)
    at org.hibernate.validator.HibernateValidator.buildValidatorFactory(HibernateValidator.java:38)
    at org.hibernate.validator.internal.engine.AbstractConfigurationImpl.buildValidatorFactory(AbstractConfigurationImpl.java:430)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是由于 Bean Validation 导致的问题。将依赖升级到如下版本即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;jakarta.validation&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jakarta.validation-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;3.0.2&amp;lt;/version&amp;gt; 
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.hibernate.validator&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;hibernate-validator&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;7.0.5.Final&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.hibernate.validator&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;hibernate-validator-annotation-processor&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;7.0.5.Final&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;选择该版本是由于该版本支持 Java8，这样可以让项目无感升级到 OpenJDK21。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;p&gt;由于该版本的 Bean Validation 的基础包名已经从 &lt;code&gt;javax.&lt;/code&gt;​ 改为 &lt;code&gt;jakarta.&lt;/code&gt;​，所以，需要修改程序，这部分工作已经有相关程序来自动完成，敬请关注： &lt;a href=&quot;https://www.diguage.com/post/optimize-code-using-openrewrite/&quot;&gt;使用 OpenRewrite 优化代码&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;JAXB&lt;/h2&gt;
&lt;p&gt;同样是由于 &lt;a href=&quot;https://openjdk.org/jeps/320&quot;&gt;JEP 320: Remove the Java EE and CORBA Modules&lt;/a&gt; 提案， 在 OpenJDK 11 中移除了 JavaEE 的相关内容，其中也包括 &lt;a href=&quot;https://jcp.org/en/jsr/detail?id=222&quot;&gt;JAXB&lt;/a&gt;。编译可能会报错，增加如下依赖即可：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.glassfish.jaxb&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jaxb-runtime&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;2.3.9&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Java 模块化&lt;/h2&gt;
&lt;p&gt;如果构建一切顺利，以为可以正常启动运行程序，结果却可能报如下错误：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not &quot;opens java.lang&quot; to unnamed module @66f57048
  at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这是由于在 JDK 9 中引入的 &lt;a href=&quot;https://openjdk.org/projects/jigsaw/spec/sotms/&quot;&gt;Java Platform Module System&lt;/a&gt; 导致的，该协议对 Java 的封装性做了进一步增强。更详细的内容可以看： ① 协议： &lt;a href=&quot;https://openjdk.org/projects/jigsaw/spec/&quot;&gt;Java Platform Module System JSR (376)&lt;/a&gt; ② 实现： &lt;a href=&quot;https://openjdk.org/jeps/261&quot;&gt;JEP 261: Module System&lt;/a&gt; ③ 解释： &lt;a href=&quot;https://nipafx.dev/java-modules-reflection-vs-encapsulation/&quot;&gt;Reflection vs Encapsulation&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;具体到该问题的解决办法也比较简单：将没开放的模块强制对外开放。有两个参数选项：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;--add-exports&lt;/code&gt; 导出包，意味着其中的所有公共类型和成员都可以在编译和运行时访问。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--add-opens&lt;/code&gt; 打开包，意味着其中的所有类型和成员（不仅是公共类型）都可以在运行时访问。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两者的区别在于 &lt;code&gt;--add-opens&lt;/code&gt;​ 开放的更加彻底，不仅 &lt;code&gt;public&lt;/code&gt;​ 类型、变量及方法可以访问，就连非 &lt;code&gt;public&lt;/code&gt;​ 元素，也可以通过调用 &lt;code&gt;setAccessible(true)&lt;/code&gt;​ 后也可以访问。简单起见，直接使用 &lt;code&gt;--add-opens&lt;/code&gt;​ 即可。相关的参数在异常中也提醒出来了： &lt;code&gt;module java.base&lt;/code&gt;​ 和 &lt;code&gt;&quot;opens java.lang&quot;&lt;/code&gt;​，结合起来，直接这样配置：在 &lt;code&gt;java&lt;/code&gt;​ 明了启动参数中，增加 &lt;code&gt;--add-opens java.base/java.lang=ALL-UNNAMED&lt;/code&gt; 选项即可。&lt;/p&gt;
&lt;p&gt;下面再列出几个相关示例：&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;java.base/java.util&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;错误日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field protected int[] java.util.Calendar.fields accessible: module java.base does not &quot;opens java.util&quot; to unnamed module @21282ed8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动参数： &lt;code&gt;--add-opens java.base/java.util=ALL-UNNAMED&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;java.base/java.math&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;错误日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java.lang.reflect.InaccessibleObjectException: Unable to make field final int[] java.math.BigInteger.mag accessible: module java.base does not &quot;opens java.math&quot; to unnamed module @21282ed8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;启动参数： &lt;code&gt;--add-opens java.base/java.math=ALL-UNNAMED&lt;/code&gt;。&lt;/p&gt;
&lt;h2&gt;构建与测试&lt;/h2&gt;
&lt;p&gt;上面介绍了程序相关的错误及解决办法，下面介绍一下构建流程中出现的问题。&lt;/p&gt;
&lt;h3&gt;maven-compiler-plugin 配置&lt;/h3&gt;
&lt;p&gt;如果项目中，在编译阶段做了一些扩展性的东西，那么就可能触发上面 &lt;a href=&quot;https://www.diguage.com/post/upgrade-to-openjdk21/#jigsaw&quot;&gt;Java 模块化&lt;/a&gt; 中描述的问题。类似如下日志：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;java.lang.IllegalAccessError: class com.diguage.plugin.lombok.ToStringProcessor (in unnamed module @0x551976c2)
cannot access class com.sun.tools.javac.api.JavacTrees (in module jdk.compiler)
because module jdk.compiler does not export com.sun.tools.javac.api to unnamed module @0x551976c2
        at com.diguage.plugin.lombok.ToStringProcessor.init(ToStringProcessor.java:44)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个问题也可以通过增加参数来完成。不过，这个参数需要在 &lt;code&gt;pom.xml&lt;/code&gt; 中通过给 maven-compiler-plugin 插件增加配置的方式来搞，如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&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-compiler-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;3.13.0&amp;lt;/version&amp;gt;
  &amp;lt;configuration&amp;gt;
      &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
      &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;
      &amp;lt;compilerArgs&amp;gt;
        &amp;lt;arg&amp;gt;-J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED&amp;lt;/arg&amp;gt;
      &amp;lt;/compilerArgs&amp;gt;
  &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;低版本的 Lombok 也会遇到类似问题，可以通过升级到高版本来解决。实在解决不了，兜底方案也可以直接在这里配置。&lt;/p&gt;
&lt;h3&gt;maven-surefire-plugin 配置&lt;/h3&gt;
&lt;p&gt;使用 Maven 进行构建或者专门执行测试时，可能也会遇到 &lt;a href=&quot;https://www.diguage.com/post/upgrade-to-openjdk21/#jigsaw&quot;&gt;Java 模块化&lt;/a&gt; 中描述的问题。同样，可以通过在 &lt;code&gt;pom.xml&lt;/code&gt; 中配置 maven-surefire-plugin 插件的方式来解决，具体如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&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-surefire-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;3.2.5&amp;lt;/version&amp;gt;
  &amp;lt;configuration&amp;gt;
      &amp;lt;skipTests&amp;gt;true&amp;lt;/skipTests&amp;gt;
      &amp;lt;includes&amp;gt;
        &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
      &amp;lt;/includes&amp;gt;
      &amp;lt;argLine&amp;gt;
        --add-opens java.base/java.lang=ALL-UNNAMED
        --add-opens java.base/java.util=ALL-UNNAMED
        --add-opens java.base/java.math=ALL-UNNAMED
        --add-opens java.base/java.time=ALL-UNNAMED
      &amp;lt;/argLine&amp;gt;
  &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;IntelliJ IDEA 配置&lt;/h3&gt;
&lt;p&gt;在 IntelliJ IDEA 运行程序，大概率也会报错，可以通过在 “VM Option” 配置项中，增加 &lt;a href=&quot;https://www.diguage.com/post/upgrade-to-openjdk21/#jigsaw&quot;&gt;Java 模块化&lt;/a&gt; 提到的相关启动参数即可正常启动。&lt;/p&gt;
&lt;h2&gt;技巧&lt;/h2&gt;
&lt;p&gt;还有一个不是问题的问题需要解决一下：目前大多数开发人员用的还是 JDK 8，如何可以让大家无痛或者无感升级呢？&lt;/p&gt;
&lt;p&gt;D瓜哥分享一个小技巧：可以使用 Maven 的 &lt;code&gt;profile&lt;/code&gt; 机制，让其根据 JDK 版本号，自动激活不同的配置。具体入戏下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&amp;gt;
&amp;lt;profile&amp;gt;
  &amp;lt;id&amp;gt;Java1.8&amp;lt;/id&amp;gt;
  &amp;lt;activation&amp;gt;
    &amp;lt;!-- 在 JDK 1.8 时自动激活--&amp;gt;
    &amp;lt;jdk&amp;gt;1.8&amp;lt;/jdk&amp;gt;
  &amp;lt;/activation&amp;gt;
  &amp;lt;properties&amp;gt;
    &amp;lt;spring.version&amp;gt;5.3.33&amp;lt;/spring.version&amp;gt; 
  &amp;lt;/properties&amp;gt;
  &amp;lt;!-- 在父 POM 中使用 dependencyManagement 生命 --&amp;gt;
  &amp;lt;!-- 在需要的子模块中可以直接使用 --&amp;gt;
  &amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt; 
        &amp;lt;artifactId&amp;gt;javax.servlet-api&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
        &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
  &amp;lt;/dependencyManagement&amp;gt;
  &amp;lt;build&amp;gt;
    &amp;lt;plugins&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-surefire-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.2.5&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
        &amp;lt;includes&amp;gt;
          &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
        &amp;lt;/includes&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-compiler-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.13.0&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
          &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
          &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;
        &amp;lt;/configuration&amp;gt;
      &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
  &amp;lt;/build&amp;gt;
&amp;lt;/profile&amp;gt;

&amp;lt;!-- @author: D瓜哥 · https://www.diguage.com --&amp;gt;
&amp;lt;profile&amp;gt;
  &amp;lt;id&amp;gt;Java21&amp;lt;/id&amp;gt;
  &amp;lt;activation&amp;gt;
    &amp;lt;jdk&amp;gt;[21,)&amp;lt;/jdk&amp;gt;
  &amp;lt;/activation&amp;gt;
  &amp;lt;properties&amp;gt;
    &amp;lt;spring.version&amp;gt;6.0.19&amp;lt;/spring.version&amp;gt; 
  &amp;lt;/properties&amp;gt;
  &amp;lt;!-- 在父 POM 中使用 dependencyManagement 生命 --&amp;gt;
  &amp;lt;!-- 在需要的子模块中可以直接使用 --&amp;gt;
  &amp;lt;dependencyManagement&amp;gt;
    &amp;lt;dependencies&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;jakarta.servlet&amp;lt;/groupId&amp;gt; 
        &amp;lt;artifactId&amp;gt;jakarta.servlet-api&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;6.0.0&amp;lt;/version&amp;gt;
        &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.openjdk.nashorn&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;nashorn-core&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;15.4&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
        &amp;lt;groupId&amp;gt;org.glassfish.jaxb&amp;lt;/groupId&amp;gt;
        &amp;lt;artifactId&amp;gt;jaxb-runtime&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;2.3.9&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;
  &amp;lt;/dependencyManagement&amp;gt;
  &amp;lt;!--在几乎所有模块都会使用，所以，直接在父 POM 中声明依赖 --&amp;gt;
  &amp;lt;dependencies&amp;gt;
    &amp;lt;dependency&amp;gt;
      &amp;lt;groupId&amp;gt;javax.annotation&amp;lt;/groupId&amp;gt;
      &amp;lt;artifactId&amp;gt;javax.annotation-api&amp;lt;/artifactId&amp;gt;
      &amp;lt;version&amp;gt;1.3.2&amp;lt;/version&amp;gt;
    &amp;lt;/dependency&amp;gt;
  &amp;lt;/dependencies&amp;gt;
  &amp;lt;build&amp;gt;
    &amp;lt;plugins&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-surefire-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.2.5&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
        &amp;lt;includes&amp;gt;
          &amp;lt;include&amp;gt;**/*Test.java&amp;lt;/include&amp;gt;
        &amp;lt;/includes&amp;gt;
        &amp;lt;argLine&amp;gt;
          --add-opens java.base/java.lang=ALL-UNNAMED
          --add-opens java.base/java.util=ALL-UNNAMED
          --add-opens java.base/java.math=ALL-UNNAMED
          --add-opens java.base/java.time=ALL-UNNAMED
        &amp;lt;/argLine&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-compiler-plugin&amp;lt;/artifactId&amp;gt;
        &amp;lt;version&amp;gt;3.13.0&amp;lt;/version&amp;gt;
        &amp;lt;configuration&amp;gt;
        &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
        &amp;lt;fork&amp;gt;true&amp;lt;/fork&amp;gt;
        &amp;lt;compilerArgs&amp;gt;
          &amp;lt;arg&amp;gt;-J--add-opens=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED&amp;lt;/arg&amp;gt;
        &amp;lt;/compilerArgs&amp;gt;
        &amp;lt;/configuration&amp;gt;
      &amp;lt;/plugin&amp;gt;
    &amp;lt;/plugins&amp;gt;
  &amp;lt;/build&amp;gt;
&amp;lt;/profile&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;开发机使用 JDK 8，所以，使用 Spring 5 + Servlet；正式环境使用 OpenJDK 21，所以，使用 Spring 6 + Jakarta Servlet。&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;p&gt;使用上面的配置，只要程序没有直接使用 Servlet API，就可以在 JDK 8 和 OpenJDK 21 之间自由切换。真正做到平稳升级。&lt;/p&gt;
&lt;h2&gt;科技与狠活&lt;/h2&gt;
&lt;p&gt;文章最后，在整一点科技与狠活。&lt;/p&gt;
&lt;h3&gt;EMT4J&lt;/h3&gt;
&lt;p&gt;关于 JDK 升级的事项，其实还有很多检查项。理想情况下，最好有工具能自动检查这些项目。关于这个问题，阿里巴巴开发了 Migration Toolkit for Java，现在已经捐给 Eclipse 基金会了，代码在 &lt;a href=&quot;https://github.com/adoptium/emt4j&quot;&gt;adoptium/emt4j: Eclipse Migration Toolkit for Java&lt;/a&gt;。这个工具还提供了 Maven 插件，所以，可以直接使用这个插件来做检查工作。具体配置如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;plugin&amp;gt;
  &amp;lt;groupId&amp;gt;org.eclipse.emt4j&amp;lt;/groupId&amp;gt;
  &amp;lt;artifactId&amp;gt;emt4j-maven-plugin&amp;lt;/artifactId&amp;gt;
  &amp;lt;version&amp;gt;0.8.0&amp;lt;/version&amp;gt;
  &amp;lt;!-- 可以将检查过程绑定到 Maven 构建周期的某个阶段，但不建议。 --&amp;gt;
  &amp;lt;!-- &amp;lt;executions&amp;gt;--&amp;gt;
  &amp;lt;!--   &amp;lt;execution&amp;gt;--&amp;gt;
  &amp;lt;!--     &amp;lt;phase&amp;gt;process-test-classes&amp;lt;/phase&amp;gt;--&amp;gt;
  &amp;lt;!--     &amp;lt;goals&amp;gt;--&amp;gt;
  &amp;lt;!--       &amp;lt;goal&amp;gt;check&amp;lt;/goal&amp;gt;--&amp;gt;
  &amp;lt;!--     &amp;lt;/goals&amp;gt;--&amp;gt;
  &amp;lt;!--   &amp;lt;/execution&amp;gt;--&amp;gt;
  &amp;lt;!-- &amp;lt;/executions&amp;gt;--&amp;gt;
  &amp;lt;configuration&amp;gt;
      &amp;lt;!-- 当前版本 --&amp;gt;
      &amp;lt;fromVersion&amp;gt;8&amp;lt;/fromVersion&amp;gt;
      &amp;lt;!-- 期望升级版本 --&amp;gt;
      &amp;lt;toVersion&amp;gt;21&amp;lt;/toVersion&amp;gt;
      &amp;lt;outputFile&amp;gt;report.html&amp;lt;/outputFile&amp;gt;
  &amp;lt;/configuration&amp;gt;
&amp;lt;/plugin&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后执行如下命令就可以对应用程序做个全面检查：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;mvn emt4j:check
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在构建目录里找 &lt;code&gt;report.html&lt;/code&gt; 文件，会有一个个超长的文件，列出成千上百个问题。（D瓜哥检查的一个应用有 2600 行的检查结果。）其实，不用担心，大部分问题可以忽略。但是，你很清楚可能潜在的问题，就像吃西药的时候，看到一大堆不良反应后，吃起来更放心。&lt;/p&gt;
&lt;h3&gt;OpenRewrite&lt;/h3&gt;
&lt;p&gt;上述工具检查出来的一部分问题，可以用另外“科技与狠活”解决，限于篇幅，这里就不展开了。敬请关注： &lt;a href=&quot;https://www.diguage.com/post/optimize-code-using-openrewrite/&quot;&gt;使用 OpenRewrite 优化代码&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;线上参数&lt;/h2&gt;
&lt;p&gt;随着 Java 的升级，Java 的启动参数也发生了不小变化。升级到 OpenJDK 21 后，原有的启动参数大概率没办法直接重用。那么，上线的时候，启动参数怎么配置呢？接下来，D瓜哥会分享一下在生产环境中的启动参数。敬请关注： &lt;a href=&quot;https://www.diguage.com/post/java-21-boot-parameters-in-the-production/&quot;&gt;生产环境中 Java 21 启动参数&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;p&gt;‍&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.diguage.com/post/upgrade-to-openjdk21/&quot;&gt;https://www.diguage.com/post/upgrade-to-openjdk21/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>语音识别</title><link>https://www.motouguai.com/posts/speech-recognition-z1wc47v/</link><guid isPermaLink="true">https://www.motouguai.com/posts/speech-recognition-z1wc47v/</guid><description>记录 FunASR 在线语音识别 CPU 运行时的镜像、项目文档与部署参考，便于后续搭建实时语音识别服务。</description><pubDate>Tue, 15 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;%%  %%&lt;/p&gt;
&lt;h1&gt;语音识别&lt;/h1&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.10&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;p&gt;https://github.com/modelscope/FunASR/blob/main/runtime/readme_cn.md&lt;/p&gt;
</content:encoded></item><item><title>utools 变量快速翻译命名插件</title><link>https://www.motouguai.com/kai-yuan/utools-variable-fast-translation-naming-plugin/</link><guid isPermaLink="true">https://www.motouguai.com/kai-yuan/utools-variable-fast-translation-naming-plugin/</guid><description>codevarutools 变量快速翻译命名插件输入 xt(小驼峰) dt(大驼峰) xh(下划线) cl(常亮)用键盘上下 选择然后回车 或者 鼠标点击选择来自动放入剪切板,并自动执行粘贴. 安装方式:utools 插件中心搜索 变量快速翻译命名插件 0.0.7 版本后不再继续提供 upx 文件版本,需要自行在 utools 中打包 功能: 翻译你输入的内</description><pubDate>Fri, 08 Nov 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;codevar&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://u.tools/&quot;&gt;utools&lt;/a&gt; 变量快速翻译命名插件
输入 xt(小驼峰) dt(大驼峰) xh(下划线) cl(常亮)
用键盘上下 选择然后回车 或者 鼠标点击选择来自动放入剪切板,并自动执行粘贴.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://ww1.sinaimg.cn/large/0076ZmKJly1g8m4bsr0hcg30tg0lywzi.gif&quot; alt=&quot;演示&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;安装方式:&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://u.tools/&quot;&gt;utools&lt;/a&gt; 插件中心搜索 &lt;code&gt;变量快速翻译命名插件&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;0.0.7&lt;/strong&gt; 版本后不再继续提供 upx 文件版本,需要自行在 utools 中打包&lt;/p&gt;
&lt;h3&gt;功能:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;翻译你输入的内容为英文&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供编程中变量命名的小驼峰, 大驼峰, 下划线, 常量格式的翻译内容&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;只需要上下翻动, 回车即可复制到剪切板&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;下载方式&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;本插件下载地址:&lt;a href=&quot;https://github.com/qiaoanqiao/codevar&quot;&gt;https://github.com/qiaoanqiao/codevar&lt;/a&gt; 自行在 utools 中打包&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;utools&lt;/code&gt; 插件中心搜索 &lt;code&gt;变量快速翻译命名插件&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;升级方式:&lt;/h3&gt;
&lt;p&gt;如果在之后的使用中. 感觉不爽了.点击插件作者链接, 然后进入插件下载地址. 看看有没有新版本吧
如果你有什么建议欢迎提出&lt;/p&gt;
&lt;h3&gt;作者后续想法&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;加上翻译列表快捷键, 不用上下按键滚动就可以直接选择&lt;/li&gt;
&lt;li&gt;界面有点 low, 需要美化&lt;/li&gt;
&lt;li&gt;不同翻译引擎设置(萝卜青菜各有所爱…)&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>mac下php手动编译debug安装会碰到的问题</title><link>https://www.motouguai.com/php-yuan-ma-jie-du/ck2pxwkcl000d788wxx44kq83/</link><guid isPermaLink="true">https://www.motouguai.com/php-yuan-ma-jie-du/ck2pxwkcl000d788wxx44kq83/</guid><description>mac 下 php手动编译 debug 安装会碰到的问题 下载7.1.0版本php源码后进行编译 1./configure --prefix=/usr/local/php7.1.0 --enable-debug --enable-fpm --with-iconv=/usr/local/lib/libiconv --with-config-file-path=</description><pubDate>Thu, 08 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;mac 下 php手动编译 debug 安装会碰到的问题&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;下载7.1.0版本&lt;code&gt;php&lt;/code&gt;源码后进行编译&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./configure --prefix=/usr/local/php7.1.0 --enable-debug --enable-fpm --with-iconv=/usr/local/lib/libiconv --with-config-file-path=/usr/local/php7.1.0/etc
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;mac 需要先切换管理用户 &lt;code&gt;sudo su&lt;/code&gt;
再执行 &lt;code&gt;make &amp;amp;&amp;amp; make install&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果碰到一些错误, 请把错误内容 分段 挑选&lt;code&gt;关键词&lt;/code&gt;百度或Google 多试试提供的解决方法;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;列出两个比较坑的错误解决流程&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/2019/08/08/15651655438696.jpg&quot; alt=&quot;-w722&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Undefined symbols for architecture x86_64:
“_libiconv”, referenced from:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Undefined symbols for architecture x86_64:
  &quot;_libiconv&quot;, referenced from:
      _zif_iconv_substr in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _php_iconv_string in iconv.o
      __php_iconv_strlen in iconv.o
      __php_iconv_strpos in iconv.o
      __php_iconv_appendl in iconv.o
      _php_iconv_stream_filter_append_bucket in iconv.o
      ...
  &quot;_libiconv_close&quot;, referenced from:
      _zif_iconv_substr in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _php_iconv_string in iconv.o
      __php_iconv_strlen in iconv.o
      __php_iconv_strpos in iconv.o
      __php_iconv_mime_decode in iconv.o
      _php_iconv_stream_filter_factory_create in iconv.o
      ...
  &quot;_libiconv_open&quot;, referenced from:
      _zif_iconv_substr in iconv.o
      _zif_iconv_mime_encode in iconv.o
      _php_iconv_string in iconv.o
      __php_iconv_strlen in iconv.o
      __php_iconv_strpos in iconv.o
      __php_iconv_mime_decode in iconv.o
      _php_iconv_stream_filter_factory_create in iconv.o
      ...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [libs/libphp7.bundle] Error 1
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;按照[同类问题](https://stackoverflow.com/questions/40167324/php-compile-fails-with-undefined-symbols-for-architecture-x86-64-libiconv-on-ma)的解决方法

在解决方法中搜索的关键词你如果搜索不到需要改成`EXTRA_LDFLAGS_PROGRAM` 或者拆分一下搜索 然后删除解决方法说的内容 记得前面加上 -
![](/images/legacy/fenxiangy/2019/08/08/15651647274096.jpg)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://bugs.php.net/bug.php?id=71343&quot;&gt;https://bugs.php.net/bug.php?id=71343&lt;/a&gt;
&lt;a href=&quot;https://juejin.im/entry/5b87a081f265da434a1fd98a&quot;&gt;https://juejin.im/entry/5b87a081f265da434a1fd98a&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>php中的变量-源码解读</title><link>https://www.motouguai.com/php-yuan-ma-jie-du/ck2pxwkcw000x788waetom6a6/</link><guid isPermaLink="true">https://www.motouguai.com/php-yuan-ma-jie-du/ck2pxwkcw000x788waetom6a6/</guid><description>变量字符串 在定义字符串 赋值给变量, 这个变量gc.u.v.type=6为字符常亮 由此可得字符常亮类型. 不手动创建内存去指向. 赋值变量赋值给另外一个变量 对于简单类型, 如: int null 会直接复制. 对于复杂类型 如 string object 会在写时复制 数组 数组变量 数组有两个类型: packed Array(索引数组) 和 Hash</description><pubDate>Thu, 08 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;变量&lt;/h1&gt;
&lt;h3&gt;字符串&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;在定义字符串 赋值给变量, 这个变量gc.u.v.type=6为字符常亮 由此可得字符常亮类型. 不手动创建内存去指向.
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/2019/08/08/15650773206179.jpg&quot; alt=&quot;-w1257&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;赋值&lt;/h3&gt;
&lt;p&gt;变量赋值给另外一个变量 对于简单类型, 如: int null 会直接复制. 对于复杂类型 如 string object 会在写时复制&lt;/p&gt;
&lt;h3&gt;数组&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;数组变量&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;数组有两个类型: packed Array(索引数组) 和 Hash Array(非索引数组) , packed 类型只有两个索引数组 而 packed 则 有八个索引数组.
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/2019/08/08/15652478760597.jpg&quot; alt=&quot;-w1124&quot; /&gt;
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/2019/08/08/15652480218652.jpg&quot; alt=&quot;-w1212&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;- 当数组中的申键超过8个则会进行`处理`申请增加为`8+8`个桶数组
- `unset`并不会删除数组所占用的内存, 而是类型变为`is_undefined`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;观看教程:
&lt;a href=&quot;http://www.imooc.com/learn/1085&quot;&gt;变量基础&lt;/a&gt;
&lt;a href=&quot;https://coding.imooc.com/class/312.html&quot;&gt;源码解析&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>mqtt协议理解</title><link>https://www.motouguai.com/note/mqttprotocol/</link><guid isPermaLink="true">https://www.motouguai.com/note/mqttprotocol/</guid><description>标签（空格分隔）： mqtt 这个协议因为公司需要做物联网方面的东西, 去工厂里面向技术人员讨论告诉我需要的一些技术,让我去琢磨. 上图很好的描述了mqtt在物联网中使用范围 由于物联网的环境是非常特别的，所以MQTT遵循以下设计原则： 精简，不添加可有可无的功能。 发布/订阅（Pub/Sub）模式，方便消息在传感器之间传递。 允许用户动态创建主题，零运维成</description><pubDate>Wed, 07 Aug 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： mqtt&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;这个协议因为公司需要做物联网方面的东西, 去工厂里面向技术人员讨论告诉我需要的一些技术,让我去琢磨.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/2019/08/07/15651399731994.jpg&quot; alt=&quot;mqtt&quot; /&gt;&lt;/p&gt;
&lt;p&gt;上图很好的描述了mqtt在物联网中使用范围&lt;/p&gt;
&lt;p&gt;由于物联网的环境是非常特别的，所以MQTT遵循以下设计原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;精简，不添加可有可无的功能。&lt;/li&gt;
&lt;li&gt;发布/订阅（Pub/Sub）模式，方便消息在传感器之间传递。&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;li&gt;理解客户端计算能力可能很低。&lt;/li&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;科普一下mqtt 一部分引用别的文章,加上我的理解;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;发布/订阅模式&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;与请求/回答这种同步模式不同，发布/定义模式解耦了发布消息的客户（发布者）与订阅消息的客户（订阅者）之间的关系，这意味着发布者和订阅者之间并不需要直接建立联系。打个比方，你打电话给朋友，一直要等到朋友接电话了才能够开始交流，是一个典型的同步请求/回答的场景；而给一个好友邮件列表发电子邮件就不一样，你发好电子邮件该干嘛干嘛，好友们到有空了去查看邮件就是了，是一个典型的异步发布/订阅的场景。
熟悉编程的同学一定非常熟悉这种设计模式了，因为它带来了这些好处：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从上面可以知道:&lt;/p&gt;
&lt;p&gt;发布者与订阅者不必了解彼此，只要认识同一个消息代理(服务端)即可。
发布者和订阅者不需要交互，发布者无需等待订阅者确认而导致锁定。
发布者和订阅者不需要同时在线，可以自由选择时间来消费消息(这个要注意消息类型)。&lt;/p&gt;
&lt;p&gt;ps:其实这种可以用生活中使用的微信形象解释这种 消息模式 :
甲给乙发送一个消息;
&lt;code&gt;(其中就相当于甲发布了一个消息,而发布消息的目标是乙订阅的主题,只是这个主题是乙收消息的主题,甲传过来的消息可以分解为:发送人,发送的消息这样的参数)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;乙不需要在线,但是在线就可以接收;&lt;/p&gt;
&lt;p&gt;乙给甲发消息;
&lt;code&gt;甲订阅了个接收消息的主题,而乙就是发到这个主题中&lt;/code&gt;
![消息发送订阅][3]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;主题&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;MQTT是通过主题对消息进行分类的，本质上就是一个UTF-8的字符串，不过可以通过反斜杠表示多个层级关系。主题并不需要创建，直接使用就是了。
主题还可以通过通配符进行过滤。其中，+可以过滤一个层级，而*只能出现在主题最后表示过滤任意级别的层级。举个例子：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code&gt;building-b/floor-5：代表B楼5层的设备。
+/floor-5：代表任何一个楼的5层的设备。
building-b/*：代表B楼所有的设备。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意，MQTT允许使用通配符订阅主题，但是并不允许使用通配符广播(发送消息)。&lt;/p&gt;
&lt;p&gt;通配符:&lt;/p&gt;
&lt;h4&gt;主题层级分隔符: &lt;code&gt;/&lt;/code&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;/&lt;/code&gt; 被用来分割主题树的每一层，并给主题空间提供分等级的结构。当两个通配符在一个主题中出现的时候，主题层次分隔符的使用是很重要的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;ps:&lt;/code&gt;类似于新闻分类中的结构 &lt;code&gt;/&lt;/code&gt; 全球新闻/中国新闻/码农新闻&lt;/p&gt;
&lt;h4&gt;单层通配符&lt;code&gt;+&lt;/code&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;+&lt;/code&gt; 只匹配主题的一层。比如说，&lt;code&gt;finance/stock/+&lt;/code&gt;匹配&lt;code&gt;finance/stock/ibm&lt;/code&gt;和&lt;code&gt;finance/stock/xyz&lt;/code&gt;，但是不匹配&lt;code&gt;finance/stock/ibm/closingprice&lt;/code&gt;。另外，因为单层通配符只匹配1层，&lt;code&gt;finance/+不匹配finance&lt;/code&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;单层通配符可以被用于主题树的任意层级，连带多层通配符。它必须被用在主题层级分隔符/的右边，除非它是指定自己。因此，&lt;code&gt;+&lt;/code&gt;和&lt;code&gt;finance/+&lt;/code&gt;都是有效的，但是&lt;code&gt;finance+&lt;/code&gt;无效。单层通配符可以用在主题树的末端，也可以用在中间。比如说，&lt;code&gt;finance/+&lt;/code&gt;和&lt;code&gt;finance/+/ibm&lt;/code&gt;都是有效的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;ps:&lt;/code&gt;匹配一层就是匹配 全球新闻/ 而订阅 码农新闻 的人并不能收到发送给 全球新闻/ 这个有通配符的主题的信息&lt;/p&gt;
&lt;h4&gt;多层通配符: &lt;code&gt;#&lt;/code&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;#&lt;/code&gt; 是一个匹配主题中任意层次数的通配符。比如说，如果你订阅了finance/stock/ibm/#，你就可以接收到以下这些主题的消息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt;finance/stock/ibm
&amp;gt;finance/stock/ibm/closingprice
&amp;gt;finance/stock/ibm/currentprice
&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;多层通配符有可以表示大于等于0的层次。因此，finance/#也可以匹配到单独的finance，在这种情况下#代表0层。在这种语境下主题层次分隔符/就没有意义了。因为没有可以分的层次。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;多层通配符只可以确定当前层或者下一层。因此，#和finance/#都是有效的，但是finance#不是有效的。多层通配符一定要是主题树的最后一个字符。比如说，finance/#是有效的，但是finance/#/closingprice是无效的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;ps:&lt;/code&gt;多层匹配就是匹配 全球新闻 下的所有子主题 订阅 码农新闻 的人能收到发送给 全球新闻/# 这个有通配符的主题的信息&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;主题语法和用法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;当你建立一个应用，设计主题树的时候应该考虑以下的主题名字的语法和语义：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;主题至少有一个字符长。&lt;/li&gt;
&lt;li&gt;主题名字是大小写敏感的。比如说，ACCOUNTS和Accounts是两个不同的主题。&lt;/li&gt;
&lt;li&gt;主题名字可以包含空格。比如，Accounts payable是一个有效的主题。&lt;/li&gt;
&lt;li&gt;以/开头会产生一个不同的主题。比如说，/finnace与finance不同。/finance匹配”+/+”和/+,但不匹配+&lt;/li&gt;
&lt;li&gt;不要在任何主题中包含null（Unicode \x0000）字符。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;以下的原则应用于主题树的建造和内容&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;在主题树中，长度被限制于64k内但是在这以内没有限制层级的数目 。
可以有任意数目的根节点；也就是说，可以有任意数目的主题树。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;服务质量&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;为了满足不同的场景，MQTT支持三种不同级别的服务质量（Quality of Service，QoS）为不同场景提供消息可靠性：&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;级别0：尽力而为。消息发送者会想尽办法发送消息，但是遇到意外并不会重试。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;级别1：至少一次。消息接收者如果没有知会或者知会本身丢失，消息发送者会再次发送以保证消息接收者至少会收到一次，当然可能造成重复消息。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;级别2：恰好一次。保证这种语义肯待会减少并发或者增加延时，不过丢失或者重复消息是不可接受的时候，级别2是最合适的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;服务质量是个老话题了。级别2所提供的不重不丢很多情况下是最理想的，不过往返多次的确认一定对并发和延迟带来影响&lt;code&gt;(不适合api)&lt;/code&gt;。级别1提供的至少一次语义在日志处理这种场景下是完全OK的，所以像Kafka这类的系统利用这一特点减少确认从而大大提高了并发。级别0适合鸡肋数据场景，食之无味弃之可惜，就这么着吧。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ps:&lt;/code&gt;所以还是用级别1写api吧.0有点不稳妥,万一哪天发送个表白消息到妹子那里,妹子没收到造成不回复你.你还以为妹子不同意,或者默认…&lt;/p&gt;
&lt;h4&gt;消息类型&lt;/h4&gt;
&lt;p&gt;MQTT拥有14种不同的消息类型(报文的类型)：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CONNECT：客户端连接到MQTT代理
CONNACK：连接确认
PUBLISH：新发布消息
PUBACK：新发布消息确认，是QoS 1给PUBLISH消息的回复
PUBREC：QoS 2消息流的第一部分，表示消息发布已记录
PUBREL：QoS 2消息流的第二部分，表示消息发布已释放
PUBCOMP：QoS 2消息流的第三部分，表示消息发布完成
SUBSCRIBE：客户端订阅某个主题
SUBACK：对于SUBSCRIBE消息的确认
UNSUBSCRIBE：客户端终止订阅的消息
UNSUBACK：对于UNSUBSCRIBE消息的确认
PINGREQ：心跳
PINGRESP：确认心跳
DISCONNECT：客户端终止连接前优雅地通知MQTT代理
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;搭配一个我在测试时所分析的服务器的消息日志更清晰看到使用:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;New connection from 192.168.1.166 on port 1883.

1520560007: New client connected from 192.168.1.166 as 036914380929367040071489983908 (c1, k60).

-新的连接 客户端连接指定的ClientID为036914380929367040071489983908 清除session  k60: 表示keep-alive=60s

1520560007: Sending CONNACK to 036914380929367040071489983908 (0, 0)

-发送连接ACK包给客户端

1520560007: Received SUBSCRIBE from 036914380929367040071489983908

-服务器收到一个来自ClientID为036914380929367040071489983908的订阅请求

1520560007:     SN69143809293670ctr (QoS 0)

-服务器识别036914380929367040071489983908订阅的主题为 SN69143809293670ctr，
指定的QOS=0遗嘱保留被设置为 0，服务端必须将遗嘱消息当作非保留消息发布

1520560007: 036914380929367040071489983908 0 SN69143809293670ctr

-给ClientID=036914380929367040071489983908客户端发送订阅SN69143809293670ctr ACK回包

1520560007: Sending SUBACK to 036914380929367040071489983908

-服务器发送内容给客户端日志

1520560017: Received PUBLISH from 036914380929367040071489983908 (d0, q0, r0, m0, &apos;SN69143809293670state&apos;, ... (99 bytes))

-服务器正在发送一个消息给ClientID=036914380929367040071489983908的客户端，消息体大小为99 bytes，消息主题为‘SN69143809293670state’
(d0, q2, r0, m0)的解释, 以下参数具体含义，参考MQTT协议
　　d: 表示mqtt报头的DUP字段
　　q: 表示的QOS字段
　　r: 表示的是RETAIN
　　m: 表示的是消息ID,即mid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;ps:&lt;/code&gt;这个东西可以参考一下官方文档; &lt;a href=&quot;https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/02-ControlPacketFormat.html#221-mqtt%E6%8E%A7%E5%88%B6%E6%8A%A5%E6%96%87%E7%9A%84%E7%B1%BB%E5%9E%8B-mqtt-control-packet-type&quot;&gt;传送门&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;MQTT代理(算是服务端了)&lt;/h4&gt;
&lt;p&gt;市面上有相当多的高质量MQTT代理，其中mosquitto是一个开源的轻量级的C实现，完全兼容了MQTT 3.1和MQTT 3.1.1。下面我们就以mosquitto为例演示一下MQTT的使用。环境是百度开放云的云服务器以及Ubuntu 14.04.1 LTS，简单起见MQTT代理和客户端都安装在同一台云服务器上了。
&lt;a href=&quot;http://www.yunda51.com/1705.html&quot;&gt;centos安装方法&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;首先SSH到云服务器，安装mosquitto以及搭配的客户端：apt-get install mosquitto
apt-get install mosquitto-clients&lt;/p&gt;
&lt;p&gt;现在在云端模拟云服务，订阅某办公楼5层的温度作为主题：&lt;/p&gt;
&lt;p&gt;mosquitto_sub -d -t ‘floor-5/temperature’
Received CONNACK
Received SUBACK
Subscribed (mid: 1): 0&lt;/p&gt;
&lt;p&gt;然后另外打开一个SSH连接，模拟温度计发送温度消息：
mosquitto_pub -d -t ‘floor-5/temperature’ -m ‘15’
Received CONNACK
Sending PUBLISH (d0, q0, r0, m1, ‘floor-5/temperature’, … (2 bytes))&lt;/p&gt;
&lt;p&gt;此时回到第一个SSH客户端可以看到信息已经接收到了，之后便是心跳消息：&lt;/p&gt;
&lt;p&gt;Received PUBLISH (d0, q0, r0, m0, ‘floor-5/temperature’, … (2 bytes))
15
Sending PINGREQ
Received PINGRESP&lt;/p&gt;
&lt;p&gt;需要注意的是mosquitto客户端默认使用QoS 0，下面我们使用QoS 2订阅这个主题：&lt;/p&gt;
&lt;p&gt;mosquitto_sub -d -q 2 -t ‘floor-5/temperature’
Received CONNACK
Received SUBACK
Subscribed (mid: 1): 2&lt;/p&gt;
&lt;p&gt;切换到另外SSH连接然后在这个主题里面发送温度消息：&lt;/p&gt;
&lt;p&gt;mosquitto_pub -d -q 2 -t ‘floor-5/temperature’ -m ‘15’
Received CONNACK
Sending PUBLISH (d0, q2, r0, m1, ‘floor-5/temperature’, … (2 bytes))
Received PUBREC (Mid: 1)
Sending PUBREL (Mid: 1)
Received PUBCOMP (Mid: 1)&lt;/p&gt;
&lt;p&gt;此时回到第一个SSH客户端可以看到信息已经接收到了，以及相应的多次握手消息：&lt;/p&gt;
&lt;p&gt;Received PUBLISH (d0, q2, r0, m1, ‘floor-5/temperature’, … (2 bytes))
Sending PUBREC (Mid: 1)
Received PUBREL (Mid: 1)
15
Sending PUBCOMP (Mid: 1)&lt;/p&gt;
&lt;p&gt;至此我们初步了解了MQTT的基本知识！接下来会发布mqtt在php和node.js中的使用文章,敬请期待;&lt;/p&gt;
</content:encoded></item><item><title>supervisor 进程管理工具 (监听、启动、停止、重启一个或多个进程或自动重启)</title><link>https://www.motouguai.com/note/supervisor-process-management-tool-listen-start-stop-restart-one-or-more-processes-autorestart/</link><guid isPermaLink="true">https://www.motouguai.com/note/supervisor-process-management-tool-listen-start-stop-restart-one-or-more-processes-autorestart/</guid><description>教程方向: 快速上手, 解决使用中遇到的一些问题使用环境: Centos7.2 安装:yum install supervisor 配置安装好后在/etc/会生成一个supervisord.conf文件及一个supervisord.d文件目录 Supervisord.conf是一些默认配置，可自行参考一些配置文件教程修改 我们主要修改 /etc/superv</description><pubDate>Mon, 08 Jul 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;教程方向: 快速上手, 解决使用中遇到的一些问题
使用环境: Centos7.2&lt;/p&gt;
&lt;h3&gt;安装:&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;yum install supervisor&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;配置&lt;/h3&gt;
&lt;p&gt;安装好后在/etc/会生成一个supervisord.conf文件及一个supervisord.d文件目录&lt;/p&gt;
&lt;p&gt;Supervisord.conf是一些默认配置，可自行参考一些配置文件教程修改&lt;/p&gt;
&lt;p&gt;我们主要修改 &lt;code&gt;/etc/supervisord.conf&lt;/code&gt; 文件的最后一行:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[include]
files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里配置的是引入型配置, 会自动引入配置的目录下的配置文件&lt;/p&gt;
&lt;p&gt;注意：[include]默认配置是制定_.ini，因个人习惯命名为_.conf文件，因此修改配置如下：&lt;/p&gt;
&lt;p&gt;我们将配置目录改为自己想要的目录下后, 在目录下建立配置文件, 以&lt;code&gt;frpc&lt;/code&gt; 为例.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/root/supervisord_conf/frpc.ini&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[program:frpc]
command=/home/vagrant/frp/frp/frpc -c /home/vagrant/frp/frp/frpc.ini
user=root
autostart=true
autorestart=true
stderr_logfile=/home/vagrant/frp/frp/err.log
stdout_logfile=/home/vagrant/frp/frp/out.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其他配置文件对应参考注释:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[program:usercenter]
directory = /home/Leon/projects/usercenter ; 程序的启动目录
command = gunicorn -w 8 -b 0.0.0.0:17510 wsgi:app  ; 启动命令
autostart = true     ; 在 supervisord 启动的时候也自动启动
Startsecs = 5        ; 启动 5 秒后没有异常退出，就当作已经正常启动了
autorestart = true   ; 程序异常退出后自动重启
Startretries = 3     ; 启动失败自动重试次数，默认是 3
user = Leon          ; 用哪个用户启动
redirect_stderr = true  ; 把 stderr 重定向到 stdout，默认 false
stdout_logfile_maxbytes = 20MB  ; stdout 日志文件大小，默认 50MB
stdout_logfile_backups = 20     ; stdout 日志文件备份数
; stdout 日志文件，需要注意当指定目录不存在时无法正常启动，所以需要手动创建目录（supervisord 会自动创建日志文件）
stdout_logfile = /data/logs/usercenter_stdout.log
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意: 配置中所指向的文件需要提前存在,否则会遇到错误.&lt;/p&gt;
&lt;h3&gt;启动并运行&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;执行:
&lt;code&gt;supervisord -c /etc/supervisord.conf&lt;/code&gt;
启动&lt;code&gt;supervisord&lt;/code&gt;服务端&lt;/p&gt;
&lt;p&gt;查看 supervisord 是否在运行：
&lt;code&gt;ps aux | grep supervisord&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;可能会碰到的错误:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;python 不推荐使用的包&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      /usr/lib/python2.7/site-packages/supervisor/options.py:383: PkgResourcesDeprecationWarning: Parameters to load are deprecated.  Call .resolve and .require separately.
return pkg_resources.EntryPoint.parse(&quot;x=&quot;+spec).load(False)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个打印并不影响使用,如果想解决这个错误可以参考 &lt;a href=&quot;https://github.com/Supervisor/supervisor/issues/617&quot;&gt;github issues&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重复启动错误
&lt;code&gt;supervisorctl unix:///var/run/supervisor.sock refused connection&lt;/code&gt;
说明 已经启动 需要执行 &lt;code&gt;supervisorctl shutdown&lt;/code&gt;终止进程再启动&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;开启了&lt;code&gt;supervisord&lt;/code&gt;后需要使用 &lt;code&gt;supervisorctl&lt;/code&gt; 管理
开启所有进程守护
&lt;code&gt;supervisorctl start all&lt;/code&gt;
再执行 &lt;code&gt;supervisorctl status&lt;/code&gt;
会看到:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    [root@localhost supervisord_conf]# supervisorctl status
frpc                             RUNNING   pid 7989, uptime 0:10:15
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其他命令&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ supervisorctl status
$ supervisorctl stop frpc
$ supervisorctl start frpc
$ supervisorctl restart frpc
$ supervisorctl reread
$ supervisorctl update

解释:
&amp;gt; status    # 查看程序状态
&amp;gt; stop usercenter   # 关闭 usercenter 程序
&amp;gt; start usercenter  # 启动 usercenter 程序
&amp;gt; restart usercenter    # 重启 usercenter 程序
&amp;gt; reread    ＃ 读取有更新（增加）的配置文件，不会启动新添加的程序
&amp;gt; update    ＃ 重启配置文件修改过的程序
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考资料
&lt;a href=&quot;http://supervisord.org/index.html&quot;&gt;官方文档&lt;/a&gt;
&lt;a href=&quot;http://liyangliang.me/posts/2015/06/using-supervisor/&quot;&gt;摘抄&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/haw2106/p/9872125.html&quot;&gt;摘抄&lt;/a&gt;
&lt;a href=&quot;https://thief.one/2018/06/01/1/&quot;&gt;感觉不错&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>开发文档案例</title><link>https://www.motouguai.com/technology-php/development-document-case/</link><guid isPermaLink="true">https://www.motouguai.com/technology-php/development-document-case/</guid><description>能愿动词为了避免歧义，文档大量使用了「能愿动词」，对应的解释如下： 必须（Must） - 只能这样子做，请无条件遵循，没有别的选项；绝不（Must Not）- 严令禁止，在任何情况下都不能这样做；应该（Should） - 强烈建议这样做，但是不强求；不应该（Should Not） - 强烈建议不这样做，但是不强求；可以（May） - 选择性高一点，在这个文档</description><pubDate>Wed, 24 Apr 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;能愿动词&lt;/h2&gt;
&lt;p&gt;为了避免歧义，文档大量使用了「能愿动词」，对应的解释如下：&lt;/p&gt;
&lt;p&gt;必须（Must） - 只能这样子做，请无条件遵循，没有别的选项；
绝不（Must Not）- 严令禁止，在任何情况下都不能这样做；
应该（Should） - 强烈建议这样做，但是不强求；
不应该（Should Not） - 强烈建议不这样做，但是不强求；
可以（May） - 选择性高一点，在这个文档内，此词语使用较少；&lt;/p&gt;
&lt;h2&gt;开发流程规范:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;应该&lt;/code&gt;使用自定义表单验证类,避免方法体过多类似功能代码段.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编写方法时&lt;code&gt;应该&lt;/code&gt;声明返回类型&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; `public function create(Create $request)
: JsonResponse {`
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;每个方法 &lt;code&gt;必须&lt;/code&gt; 写上规范注释.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;用户信息访问 &lt;code&gt;应该&lt;/code&gt; 使用Auth门面, Auth已经过框架自动载入,具体使用方法参照现有代码.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;应该&lt;/code&gt; 使用一个&lt;code&gt;return&lt;/code&gt; 进行数据返回.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;固定值访问&lt;code&gt;应该&lt;/code&gt; 使用config()访问语义化词汇获得 如&lt;code&gt;config(&apos;common_config.premium.min&apos;)&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编写业务代码时遵循依赖框架原则,框架可以提供便利的尽量使用框架提供的功能.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;controller&lt;/code&gt;层仅作为基础判断使用,繁杂业务逻辑 &lt;code&gt;应该&lt;/code&gt; 在Service层进行处理.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对存入数据的操作&lt;code&gt;应该&lt;/code&gt;使用模型处理.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对一对多,多对多,多对一等模型数据访问时,&lt;code&gt;尽量&lt;/code&gt; 使用框架自带的&lt;a href=&quot;https://laravel-china.org/docs/laravel/5.6/eloquent-relationships/1404&quot;&gt;模型关联功能&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;关键性操作流程 &lt;code&gt;应该&lt;/code&gt; 注入 &lt;a href=&quot;https://laravel-china.org/docs/laravel/5.6/events/1389&quot;&gt;事件&lt;/a&gt; 方便业务功能.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据库表增删改 &lt;code&gt;必须&lt;/code&gt; 使用&lt;a href=&quot;https://laravel-china.org/docs/laravel/5.6/migrations/1400&quot;&gt;数据库迁移&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建表后&lt;code&gt;应该&lt;/code&gt;编写相应的数据工厂文件.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;开发时&lt;code&gt;应该&lt;/code&gt;先编写对应的单元测试.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;应该&lt;/code&gt; 对表单数据进行类型校验,可以在表单验证中加上.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其他规范&lt;code&gt;应该&lt;/code&gt;参照: &lt;a href=&quot;https://laravel-china.org/docs/laravel-specification/5.5&quot;&gt;Laravel 项目开发规范&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;接口&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;请求
接口 &lt;code&gt;必须&lt;/code&gt; 统一使用&lt;code&gt;api&lt;/code&gt;路由, &lt;code&gt;POST&lt;/code&gt;请求统一放置在POST请求路由组;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST&lt;/code&gt; 请求路由 &lt;code&gt;必须&lt;/code&gt; 使用 post 路由前缀, 中间件&lt;code&gt;应该&lt;/code&gt; 使用与之相对的中间件&lt;/li&gt;
&lt;li&gt;表单校验:接口路由指向的方法中请求信息参数 &lt;code&gt;必须&lt;/code&gt; 使用自定表单验证类依赖注入校验表单填写是否正确, 自定义表单验证类中 应在类体中 使用 &lt;code&gt;use UnifiedFormat;&lt;/code&gt; 处理表单验证类自动处理的返回内容适用到项目.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Api的路由 &lt;code&gt;必须&lt;/code&gt; 使用 &lt;code&gt;name&lt;/code&gt; 方法标注, 标注中以 &lt;code&gt;.&lt;/code&gt; 分隔, 标注代表着此接口的权限管理项的标注, 用于后期添加权限; 注意标注的末尾动作如下表格, 其他行为&lt;code&gt;应该&lt;/code&gt;使用功能翻译英文标记&lt;/p&gt;
&lt;p&gt;Api.&lt;code&gt;前缀&lt;/code&gt;.&lt;code&gt;功能(英文并可以多个 . 分隔)&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;show&lt;/td&gt;
&lt;td&gt;获取资源，单个&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;index&lt;/td&gt;
&lt;td&gt;获取资源，多个&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;create&lt;/td&gt;
&lt;td&gt;创建资源&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PATCH&lt;/td&gt;
&lt;td&gt;更新资源，客户端提供部分的资源数据&lt;/td&gt;
&lt;td&gt;否&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DELETE&lt;/td&gt;
&lt;td&gt;删除资源&lt;/td&gt;
&lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;应该&lt;/code&gt; 使用 &lt;code&gt;api 资源&lt;/code&gt; 返回数据资源.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;响应
响应使用Res门面 &lt;code&gt;use Res;&lt;/code&gt;
可使用具体方法在 &lt;code&gt;app/Http/Controllers/Auth/Api/ResponseMsg.php&lt;/code&gt;
具体使用规则参考部分接口控制器代码&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;注意事项&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;使用复杂多表查询时注意&lt;code&gt;软删除&lt;/code&gt;和一些模型无感知提供的功能的处理.&lt;/li&gt;
&lt;li&gt;编写代码之前 &lt;code&gt;应该&lt;/code&gt; 读懂 &lt;a href=&quot;https://laravel-china.org/docs/laravel/5.7/lifecycle/2248&quot;&gt;框架核心架构&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;api系统剥离&lt;/h2&gt;
&lt;p&gt;只需要修改auth &lt;code&gt;config/auth.php&lt;/code&gt; defaults=&amp;gt;guard 三维数组中 web 变为 otcapi, apiverify中间件中handle方法 注释内容开启, 未注释内容注释&lt;/p&gt;
</content:encoded></item><item><title>larval-admin拓展-使用备注</title><link>https://www.motouguai.com/technology-php/larvaladmin-extension-use-notes/</link><guid isPermaLink="true">https://www.motouguai.com/technology-php/larvaladmin-extension-use-notes/</guid><description>主要布局类Encore\Admin\Form类用于生成基于数据模型的表单，先来个例子，中数据库有movies表 Encore\Admin\Grid类用于生成基于数据模型的表格，先来个例子，中数据库有movies表 Model-grid默认有两个行操作编辑和删除，可以通过下面的方式关闭它们： Model-grid内置了很多对于列的操作方法，可以通过这些方法很灵</description><pubDate>Wed, 13 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h3&gt;主要布局类&lt;/h3&gt;
&lt;p&gt;Encore\Admin\Form类用于生成基于数据模型的表单，先来个例子，中数据库有movies表&lt;/p&gt;
&lt;p&gt;Encore\Admin\Grid类用于生成基于数据模型的表格，先来个例子，中数据库有movies表&lt;/p&gt;
&lt;p&gt;Model-grid默认有两个行操作编辑和删除，可以通过下面的方式关闭它们：&lt;/p&gt;
&lt;p&gt;Model-grid内置了很多对于列的操作方法，可以通过这些方法很灵活的操作列数据。&lt;/p&gt;
&lt;p&gt;在model-grid的头部默认有批量删除和刷新两个操作工具，如果有更多的操作需求，model-grid提供了自定义工具的功能,下面的示例添加一个性别分类选择的按钮组工具。&lt;/p&gt;
&lt;p&gt;Model-grid提供了一系列的方法实现表格数据的查询过滤：&lt;/p&gt;
&lt;p&gt;Model-form使用laravel的验证规则来验证表单提交的数据：&lt;/p&gt;
&lt;p&gt;Model-form目前提供了下面几个方法来接收 保存 回调函数：&lt;/p&gt;
&lt;p&gt;Encore\Admin\Show用来显示数据详情，先来个例子，中数据库有posts表：&lt;/p&gt;
&lt;p&gt;通过可以model-tree来实现一个树状组件，可以用拖拽的方式实现数据的层级，排序等操作，下面是基本的用法。&lt;/p&gt;
&lt;p&gt;在页面调用下面的方法，它将会调用toastr组件，在页面的右上角添加一条浮动的提示&lt;/p&gt;
&lt;p&gt;Encore\Admin\Widgets\Box用来生成box组件：&lt;/p&gt;
&lt;h3&gt;使用方式&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;创建模型对应的增删改查控制器和模型 &lt;code&gt;php artisan admin:make UserController --model=App\\User&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在 &lt;code&gt;web.php&lt;/code&gt; 中添加资源访问路由 &lt;code&gt;$router-&amp;gt;resource(&apos;users&apos;, UserController::class);&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在后台系统 链接:&lt;code&gt;/admin/auth/menu&lt;/code&gt; 中添加左侧菜单栏连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;剩下的工作就是构建数据表格和表单了，打开 app/Admin/Contollers/UserController.php,找到show()、grid()和form()方法，然添加构建代码更多详细使用请查看model-grid和model-form。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;上手感触&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在使用这个后台系统中, 如果按照设计图来弄不是太理想和方便, 例如表单太长只能用自带的 &lt;a href=&quot;https://laravel-admin.org/docs/zh/model-form-fields#model-form-tab&quot;&gt;选项卡切换分组方式&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;model-form-tab
如果表单元素太多,会导致form页面太长, 这种情况下可以使用tab来分隔form:&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于列和行 属于栅栏式布局&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于有些需求效果可能还需要做接口&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>阿里云日志服务监控访问日志</title><link>https://www.motouguai.com/note/alibaba-cloud-log-service-monitors-access-logs/</link><guid isPermaLink="true">https://www.motouguai.com/note/alibaba-cloud-log-service-monitors-access-logs/</guid><description>添加日志服务 网址 点击创建Project 名称填好,所属区域选择需要监控的服务器的所在区域 接下来会出现弹出窗: 点击创建,或不小心关掉 点击名称进入下列2图界面 创建Logstore 这些根据提示填写好就行了. 数据接入 点击确认会出现此框点击数据接入向导,如果没有在2图数据接入想到下面有个按钮点几下 选择你需要的 - 配置规则. 这里要注意的只有日志路</description><pubDate>Mon, 18 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;添加日志服务
&lt;a href=&quot;https://sls.console.aliyun.com&quot;&gt;网址&lt;/a&gt;
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414710881986.jpg&quot; alt=&quot;-w1425&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;点击创建Project
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414711185213.jpg&quot; alt=&quot;-w612&quot; /&gt;&lt;/li&gt;
&lt;li&gt;名称填好,所属区域选择需要监控的服务器的所在区域
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414712242692.jpg&quot; alt=&quot;-w575&quot; /&gt;&lt;/li&gt;
&lt;li&gt;接下来会出现弹出窗:
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414712613759.jpg&quot; alt=&quot;-w770&quot; /&gt;&lt;/li&gt;
&lt;li&gt;点击创建,或不小心关掉 点击名称进入下列2图界面
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414713220423.jpg&quot; alt=&quot;-w136&quot; /&gt;
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414713504282.jpg&quot; alt=&quot;-w1438&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;创建Logstore
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414714359486.jpg&quot; alt=&quot;-w600&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;这些根据提示填写好就行了.
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414714792698.jpg&quot; alt=&quot;-w595&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据接入&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;点击确认会出现此框点击数据接入向导,如果没有在2图数据接入想到下面有个按钮点几下
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414715276043.jpg&quot; alt=&quot;-w1392&quot; /&gt;
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414716281722.jpg&quot; alt=&quot;-w369&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;选择你需要的&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414716463910.jpg&quot; alt=&quot;-w1556&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置规则.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414716660237.jpg&quot; alt=&quot;-w831&quot; /&gt;&lt;/p&gt;
&lt;p&gt;这里要注意的只有日志路径, 注意仔细看备注.我的是:
第一个选项:/wwwlogs 第二个选框: *.log&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414719024767.jpg&quot; alt=&quot;-w807&quot; /&gt;&lt;/p&gt;
&lt;p&gt;如果担心自己获取到了,但是不显示也不知道出现什么问题,那就展开高级选项按照如图配置&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414720245880.jpg&quot; alt=&quot;-w815&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;填写好后点击下一步这一步比较重要,是能不能获取到日志的关键&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414719326781.jpg&quot; alt=&quot;-w1243&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;关于机器组:需要用到阿里云的教程搭建个日志服务
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;点击创建机器组&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414721533813.jpg&quot; alt=&quot;-w585&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;点击帮助 进入https://help.aliyun.com/document_detail/28982.html?spm=5176.2020520112.116.d11.8c2434c0IPMoLR
安装Logtail;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;点击安装方式中的一个&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414722166217.jpg&quot; alt=&quot;-w431&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;我选的是阿里云内网,因为是阿里的机器
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;执行命令安装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414722753454.jpg&quot; alt=&quot;-w851&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414723283276.jpg&quot; alt=&quot;-w839&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;安装成功
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;填写信息:&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414724253308.jpg&quot; alt=&quot;-w593&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;根据日志服务里选择的区域,再填入ip
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;随后点击应用到机器组&lt;/li&gt;
&lt;li&gt;进入机器组列表&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414724912946.jpg&quot; alt=&quot;-w1619&quot; /&gt;
机器的操作中的查看状态&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414725230818.jpg&quot; alt=&quot;-w604&quot; /&gt;&lt;/p&gt;
&lt;p&gt;心跳ok就没问题&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;监控分析
&lt;ul&gt;
&lt;li&gt;随后点击日志库:&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414725700027.jpg&quot; alt=&quot;-w1531&quot; /&gt;
- 点击查询分析下的查询:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414726108799.jpg&quot; alt=&quot;-w1469&quot; /&gt;
点确定
- 右上角有开启索引&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414726404859.jpg&quot; alt=&quot;-w233&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;出现这个,我的是nginx所以点nginx模板&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414726736162.jpg&quot; alt=&quot;-w1096&quot; /&gt;&lt;/p&gt;
&lt;p&gt;然后等待一分钟左右,期间可在这里点监控&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414727628422.jpg&quot; alt=&quot;-w989&quot; /&gt;
- 如果没有数据检查:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414729350670.jpg&quot; alt=&quot;-w1423&quot; /&gt;
点击蓝色名字配置&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414729153170.jpg&quot; alt=&quot;-w1033&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414730202685.jpg&quot; alt=&quot;-w993&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2019/02/18/15414739579688.jpg&quot; alt=&quot;-w627&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/06/15414730595289.jpg&quot; alt=&quot;-w375&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;左边有些选项均有文档,仔细看&lt;/strong&gt;&lt;/p&gt;
</content:encoded></item><item><title>laravel服务提供者和门面及契约整理</title><link>https://www.motouguai.com/note/laravel-service-provider-and-facade-contract/</link><guid isPermaLink="true">https://www.motouguai.com/note/laravel-service-provider-and-facade-contract/</guid><description>标签（空格分隔）： laravel 服务提供者通俗意思是:你家需要水,服务提供者送水的;服务提供者生成后的代码 Contracts, ServiceContainer, ServiceProvider, Facades关系概念Contracts 合同，契约，也就是接口，定义一些规则，每个实现此接口的都要实现里面的方法 ServiceContainer 实现C</description><pubDate>Mon, 18 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： laravel&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;服务提供者&lt;/h2&gt;
&lt;p&gt;通俗意思是:你家需要水,服务提供者送水的;
服务提供者生成后的代码&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Contracts, ServiceContainer, ServiceProvider, Facades关系
概念
Contracts 合同，契约，也就是接口，定义一些规则，每个实现此接口的都要实现里面的方法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ServiceContainer 实现Contracts,具体的逻辑实现&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ServiceProvider ServiceContainer的服务提供者，返回ServiceContainer的实例化，供其他地方使用，可以把它加入到app/config的provider中，会被自动注册到容器中&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Facades 简化ServiceProvider的调用方式，而且可以静态调用ServiceContainer中的方法&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;code&gt;php artisan make:provider FooServiceProvider&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\lib\Tools\FooBar\FooBar;

class FooServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {

    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中boot在框架加载初期就载入就提供,如果你提供的水还需要矿物质什么的(框架内一些依赖) 就不要在这里进行提供;&lt;/p&gt;
&lt;p&gt;在一个继承服务提供者的文件内
boot方法
register方法都可以使用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$this-&amp;gt;app-&amp;gt;bind(&apos;test&apos;,function(){
    return new Test();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;方式提供依赖
这种写法理解思路可以参照:&lt;a href=&quot;http://laravelacademy.org/post/769.html&quot;&gt;链接&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在平时方法中使用:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public function two($id=null){
    //从系统容器中获取实例化对象
//    $myfoo = app(&apos;test&apos;);
//    app()-&amp;gt;make(&apos;test&apos;);
    $myfoo = \App::make(&apos;test&apos;);
    echo $myfoo-&amp;gt;get();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;或在 方法参数中加上依赖地址或名称;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;use App\lib\Tools\FooBar\Test;

public function index(Test $test)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;根据文章:&lt;a href=&quot;https://www.cnblogs.com/51fx/p/7004463.html&quot;&gt;地址&lt;/a&gt;整理思路&lt;/p&gt;
&lt;h2&gt;门面&lt;/h2&gt;
&lt;p&gt;门面定义&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;namespace App\CustomFacades;

use Illuminate\Support\Facades\Facade;

class Foo extends Facade
{

    protected static function getFacadeAccessor()
    {
        return &apos;test&apos;;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;继承Illuminate\Support\Facades\Facade
getFacadeAccessor()中return ‘test’
代表服务提供者代码中&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$this-&amp;gt;app-&amp;gt;bind(&apos;test&apos;,function(){
    return new Test();
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;的test&lt;/p&gt;
&lt;p&gt;在app.php &lt;code&gt;aliases&lt;/code&gt; 数组中添加
‘Foo’ =&amp;gt; App\CustomFacades\Foo::class,&lt;/p&gt;
&lt;h2&gt;契约&lt;/h2&gt;
&lt;p&gt;参考网址:&lt;a href=&quot;https://www.jb51.net/article/135189.htm&quot;&gt;https://www.jb51.net/article/135189.htm&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/redirect/p/6087810.html&quot;&gt;https://www.cnblogs.com/redirect/p/6087810.html&lt;/a&gt;
&lt;a href=&quot;http://laravelacademy.org/post/769.html&quot;&gt;http://laravelacademy.org/post/769.html&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/cyforever/p/6139109.html&quot;&gt;https://www.cnblogs.com/cyforever/p/6139109.html&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>对接币种钱包 资料整理</title><link>https://www.motouguai.com/note/docking-currency-wallet/</link><guid isPermaLink="true">https://www.motouguai.com/note/docking-currency-wallet/</guid><description>https://blog.csdn.net/rejames/article/details/82884508 https://github.com/aceat64/EasyBitcoin-PHP https://blog.csdn.net/wudwolf/article/details/79190084 https://bitcoin.org/en/deve</description><pubDate>Wed, 12 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/rejames/article/details/82884508&quot;&gt;https://blog.csdn.net/rejames/article/details/82884508&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/aceat64/EasyBitcoin-PHP&quot;&gt;https://github.com/aceat64/EasyBitcoin-PHP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/wudwolf/article/details/79190084&quot;&gt;https://blog.csdn.net/wudwolf/article/details/79190084&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bitcoin.org/en/developer-reference#raw-transaction-format&quot;&gt;https://bitcoin.org/en/developer-reference#raw-transaction-format&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/rejames/article/details/82885483&quot;&gt;https://blog.csdn.net/rejames/article/details/82885483&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;合约币
&lt;a href=&quot;https://hk.saowen.com/a/96d9c72062eed314bab4a1353d6de0f0cd492909fd8704c1f0eb2e674c8d670d&quot;&gt;https://hk.saowen.com/a/96d9c72062eed314bab4a1353d6de0f0cd492909fd8704c1f0eb2e674c8d670d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://hk.saowen.com/a/a3c33a6d50f274e9e0600a996442942194a681a6eeaf8962c1a04870ac96c320&quot;&gt;https://hk.saowen.com/a/a3c33a6d50f274e9e0600a996442942194a681a6eeaf8962c1a04870ac96c320&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://fenxiangy-ftp.test.upcdn.net/note/media/15446065815973/15446098239922.jpg&quot; alt=&quot;-w1562&quot; /&gt;￼&lt;/p&gt;
</content:encoded></item><item><title>grpc生成php代码(composer)</title><link>https://www.motouguai.com/note/grpc-generates-php-code-composer/</link><guid isPermaLink="true">https://www.motouguai.com/note/grpc-generates-php-code-composer/</guid><description>解决朋友不会编译问题写的备注 先去下载源码包https://github.com/protocolbuffers/protobuf/releases 解压后进入目录里面运行 12./configure --prefix=/usr/local/protobufmake &amp;amp;&amp;amp; make install 获取.proto的文件放到指定目录 在指定文</description><pubDate>Wed, 21 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;解决朋友不会编译问题写的备注&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先去下载源码包&lt;a href=&quot;https://github.com/protocolbuffers/protobuf/releases&quot;&gt;https://github.com/protocolbuffers/protobuf/releases&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;解压后进入目录里面运行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./configure --prefix=/usr/local/protobuf
make &amp;amp;&amp;amp; make install
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;获取.proto的文件放到指定目录&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在指定文件目录执行:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/usr/local/protoc/bin/protoc --php_out=.  zpt.proto
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;文档:&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/reference/php-generated&quot;&gt;https://developers.google.com/protocol-buffers/docs/reference/php-generated&lt;/a&gt;
参考:
&lt;a href=&quot;https://my.oschina.net/laixhe/blog/1476644&quot;&gt;https://my.oschina.net/laixhe/blog/1476644&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/chunguang/p/5618588.html&quot;&gt;https://www.cnblogs.com/chunguang/p/5618588.html&lt;/a&gt;
&lt;a href=&quot;https://github.com/protocolbuffers/protobuf/tree/master/php&quot;&gt;https://github.com/protocolbuffers/protobuf/tree/master/php&lt;/a&gt;
&lt;a href=&quot;https://developers.google.com/protocol-buffers/docs/downloads&quot;&gt;https://developers.google.com/protocol-buffers/docs/downloads&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>php 数据转json 中文转码问题</title><link>https://www.motouguai.com/note/php-data-to-json-chinese-transcoding-problem/</link><guid isPermaLink="true">https://www.motouguai.com/note/php-data-to-json-chinese-transcoding-problem/</guid><description>我们知道, 用PHP的json_encode来处理中文的时候, 中文都会被编码, 变成不可读的, 类似”\u***”的格式, 还会在一定程度上增加传输的数据量. &amp;lt;?php echo json_encode(&amp;quot;中文&amp;quot;); //&amp;quot;\u4e2d\u6587&amp;quot;这就让我们这些在天朝做开发的同学, 很是头疼, 有的时候还不</description><pubDate>Wed, 31 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;我们知道, 用PHP的json_encode来处理中文的时候, 中文都会被编码, 变成不可读的, 类似”\u***”的格式, 还会在一定程度上增加传输的数据量.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
echo json_encode(&quot;中文&quot;);

//&quot;\u4e2d\u6587&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就让我们这些在天朝做开发的同学, 很是头疼, 有的时候还不得不自己写json_encode.&lt;/p&gt;
&lt;p&gt;而在PHP5.4, 这个问题终于得以解决, Json新增了一个选项: JSON_UNESCAPED_UNICODE, 故名思议, 就是说, Json不要编码Unicode.&lt;/p&gt;
&lt;p&gt;看下面的例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
echo json_encode(&quot;中文&quot;, JSON_UNESCAPED_UNICODE);

//&quot;中文&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;怎么样, 是不是让大家很开心的改动? 呵呵, 当然, Json在5.4还加入了: JSON_BIGINT_AS_STRING, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES等选项, 如果有兴趣, 大家可以参看: json_encode&lt;/p&gt;
&lt;p&gt;不过, 还是要提醒下: PHP 5.4还处于开发阶段, 在最终release之前, 任何新特性都可能被调整或者更改. 如果大家有任何建议, 也欢迎反馈, 帮助我们使得PHP变得更好.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本文转载文章 &lt;a href=&quot;http://www.laruence.com/2011/10/10/2239.html&quot;&gt;http://www.laruence.com/2011/10/10/2239.html&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>单元测试文档学习笔记</title><link>https://www.motouguai.com/note/unit-test-document-study-notes/</link><guid isPermaLink="true">https://www.motouguai.com/note/unit-test-document-study-notes/</guid><description>注意事项: 编写单元测试,方法块注释不随意填写, 防止出现使用单元测试提供的注释语法无法使用 注释依赖(测试中的流程控制) 当某个测试所依赖的测试 失败时，PHPUnit 会跳过这个测试。 例如:测试a 需要 测试b获取的值 来进行测试a的测试;可以用注释依赖进行值传递 如果测试同时从 @dataProvider 方法和一个或多个 @depends 测试接收</description><pubDate>Wed, 24 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;注意事项:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;编写单元测试,方法块注释不随意填写, 防止出现使用单元测试提供的注释语法无法使用&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;注释依赖(测试中的流程控制)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;当某个测试所依赖的测试&lt;/li&gt;
&lt;li&gt;失败时，PHPUnit 会跳过这个测试。
例如:测试a 需要 测试b获取的值 来进行测试a的测试;
可以用注释依赖进行值传递&lt;/li&gt;
&lt;li&gt;如果测试同时从 @dataProvider 方法和一个或多个 @depends 测试接收数据，那么来自于数据供给器的参数将先于来自所依赖的测试的。来自于所依赖的测试的参数对于每个数据集都是一样的。&lt;/li&gt;
&lt;li&gt;如果一个测试依赖于另外一个使用了数据供给器的测试，仅当被依赖的测试至少能在一组数据上成功时，依赖于它的测试才会运行。使用了数据供给器的测试，其运行结果是无法注入到依赖于此测试的其他测试中的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;详细使用参考: &lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/writing-tests-for-phpunit.html#id7&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;数据供给器(自动迭代)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;测试a 需要多种数据进行测试, 用数据供给器后,会自动迭代测试数据供给器提供的数据进行测试.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;测试方法可以接受任意参数。这些参数由数据供给器方法（在 writing-tests-for-phpunit.data-providers.examples.DataTest.php&lt;code&gt;中，是 ``additionProvider()&lt;/code&gt; 方法）提供。用 @dataProvider 标注来指定使用哪个数据供给器方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;数据供给器方法必须声明为 &lt;code&gt;public&lt;/code&gt;，其返回值要么是一个数组，其每个元素也是&lt;code&gt;数组&lt;/code&gt;；要么是一个实现了 Iterator 接口的对象，在对它进行迭代时每步产生一个数组。每个数组都是测试数据集的一部分，将以它的内容作为参数来调用测试方法。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example 2.5 使用返回数组的数组的数据供给器&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
use PHPUnit\Framework\TestCase;

class DataTest extends TestCase
{
    /**
     * @dataProvider additionProvider
     */
    public function testAdd($a, $b, $expected)
    {
        $this-&amp;gt;assertEquals($expected, $a + $b);
    }

    public function additionProvider()
    {
        return [
            [0, 0, 0],
            [0, 1, 1],
            [1, 0, 1],
            [1, 1, 3]
        ];
    }
}
?&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;详细使用参考: &lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/writing-tests-for-phpunit.html#id10&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;测试出现异常:&lt;/h4&gt;
&lt;p&gt;标注来测试被测代码中是否抛出了异常。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;php原生异常
使用&lt;code&gt;PHPUnit\Framework\Error&lt;/code&gt; 来注释&lt;/p&gt;
&lt;p&gt;&lt;code&gt;PHPUnit\Framework\Error\Notice&lt;/code&gt; 和 &lt;code&gt;PHPUnit\Framework\Error\Warning&lt;/code&gt; 分别代表 PHP 通知与 PHP 警告。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果测试依靠会触发错误的 PHP 函数，例如 fopen ，有时候在测试中使用错误抑制符会很有用。通过抑制住错误通知，就能对返回值进行检查，否则错误通知将会导致抛出 PHPUnit\Framework\Error\Notice。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;对异常进行测试是越明确越好的。对太笼统的类进行测试有可能导致不良副作用。因此，不再允许用 @expectedException 或 setExpectedException() 对 Exception 类进行测试。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;测试的功能或代码, 编写的测试运行后断言肯定会抛出异常,可以用&lt;code&gt;@expectException&lt;/code&gt;指定抛出的异常类型;如果抛出异常类型同注释异常类型一致,结果为测试成功;&lt;/p&gt;
&lt;p&gt;@expectedExceptionCode (异常错误码)、@expectedExceptionMessage (异常信息)和 @expectedExceptionMessageRegExp (异常信息正则匹配)&lt;/p&gt;
&lt;p&gt;详细使用参考: &lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/writing-tests-for-phpunit.html#id11&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;对输出进行测试(echo等)&lt;/h4&gt;
&lt;p&gt;如&lt;code&gt;echo&lt;/code&gt;, &lt;code&gt;print&lt;/code&gt;. &lt;em&gt;单元测试使用输出缓冲区控制方式获取此内容&lt;/em&gt; 详见&lt;a href=&quot;http://php.net/manual/zh/ref.outcontrol.php&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;方法:&lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/writing-tests-for-phpunit.html#writing-tests-for-phpunit-output-tables-api&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/writing-tests-for-phpunit.html#id16&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;phpunit可生成日志(搭配Xdebug)&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/textui.html#id2&quot;&gt;文档&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;基镜(测试基础环境)&lt;/h4&gt;
&lt;p&gt;在执行测试时,有时需要预先搭建测试环境.
类似于php的魔术方法行为;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/fixtures.html#fixtures&quot;&gt;手册&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;测试替身&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;桩件
在桩件中,创建测试所需要的对象,所需要的对象可能依赖或者创建复杂使用难度高&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;有时候对被测系统(SUT)进行测试是很困难的，因为它依赖于其他无法在测试环境中使用的组件。这有可能是因为这些组件不可用，它们不会返回测试所需要的结果，或者执行它们会有不良副作用。在其他情况下，我们的测试策略要求对被测系统的内部行为有更多控制或更多可见性。
使用桩件可以替换掉被测试系统所依赖的实际组件;返回配置好返回值的测试替身(桩件)的方法称为上桩;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;可以固定简单返回值,也可以使用变量实现更复杂的上桩&lt;code&gt;willReturn($value)&lt;/code&gt; or &lt;code&gt;will($this-&amp;gt;returnValue($value))&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;返回对桩件对象的引用&lt;code&gt;will($this-&amp;gt;returnSelf());&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;不同参数对应的不同返回值方式上桩&lt;code&gt;returnValueMap(array $map);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;让上桩方法返回回调函数或方法的结果&lt;code&gt;returnCallback()&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;直接给出期望返回值的列表&lt;code&gt;will($this-&amp;gt;onConsecutiveCalls(2, 3, 5, 7));&lt;/code&gt;调用顺序返回&lt;/li&gt;
&lt;li&gt;抛出异常&lt;code&gt;will($this-&amp;gt;throwException(new Exception));&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;仿件对象
使用仿件对象，主要的功能是验证预期的行为，作为观察点来核实被测试系统在测试中的间接输出。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;方法的执行次数&lt;code&gt;expects($this-&amp;gt;once())-&amp;gt;method(&apos;update&apos;)&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;传入方法的参数&lt;code&gt;with($this-&amp;gt;equalTo(&apos;something&apos;));&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对特质(Trait)与抽象类进行模仿&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对 Web 服务(Web Services)进行上桩或模仿&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对文件系统进行模仿&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt;public function testMockBuy()
{
    $appleMock = $this-&amp;gt;getMockBuilder(Apple::class)
                      -&amp;gt;setMethods([&apos;getPrice&apos;, &apos;buy&apos;])
                      -&amp;gt;getMock();
    //建立预期情况，buy方法会被调用一次
    $appleMock-&amp;gt;expects($this-&amp;gt;once())
              -&amp;gt;method(&apos;buy&apos;);
    $this-&amp;gt;custom-&amp;gt;buy($appleMock, 10);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://phpunit.readthedocs.io/zh_CN/latest/test-doubles.html#test-doubles-stubs&quot;&gt;文档地址&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>phpstorm珍藏常用快捷键</title><link>https://www.motouguai.com/note/phpstorm-collection-common-shortcuts/</link><guid isPermaLink="true">https://www.motouguai.com/note/phpstorm-collection-common-shortcuts/</guid><description>设置项 自动定位 (定位编辑文件所在的位置) Project面板，工具图标按钮（齿轮形状），弹出的菜单中选择 Autoscroll from Source 编辑文件时，左侧文件夹聚焦到该文件 手动定位-快捷键 在编辑的所选文件按ALT+F1, 然后选择PROJECT VIEW(新版下一级 Project) PHP手册 Preferences -&amp;gt; To</description><pubDate>Thu, 18 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;设置项&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;自动定位
(定位编辑文件所在的位置)
Project面板，工具图标按钮（齿轮形状），弹出的菜单中选择
Autoscroll from Source
编辑文件时，左侧文件夹聚焦到该文件
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/17/15397452072501.jpg&quot; alt=&quot;PhpStorm 自动定位当前文件设置&quot; /&gt;
手动定位-快捷键&lt;/p&gt;
&lt;p&gt;在编辑的所选文件按ALT+F1, 然后选择PROJECT VIEW(新版下一级 Project)
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/17/15397452214724.jpg&quot; alt=&quot;PhpStorm 通过 Alt+F1 定位到 Project 视图&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PHP手册&lt;/p&gt;
&lt;p&gt;Preferences -&amp;gt; Tools-&amp;gt;External Tools
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/17/15397453688276.jpg&quot; alt=&quot;PhpStorm External Tools 中的 PHP 手册配置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Parameters参数&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://php.net/manual/zh/function.$SelectedText$.php&quot;&gt;http://php.net/manual/zh/function.$SelectedText$.php&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;注意： SelectedText
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启动的时候不打开工程文件&lt;/p&gt;
&lt;p&gt;Preferences-&amp;gt;Appearance &amp;amp; Behavior -&amp;gt;System Settings
去掉 Reopen last project on startup.up.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;使用功能&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;语法分析 Inspect Code&lt;/p&gt;
&lt;p&gt;语法分析非常有用
右击 文件夹或文件，在菜单中选择 Inspect Code，会弹出 让你选择是指定目录文件或者还是整个项目&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;常用代码片段&lt;/p&gt;
&lt;p&gt;CTRL(cmd) + j能够快捷的输入常用的代码片段，类似vim的 snipMate，可以自定义代码片段&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码格式化&lt;/p&gt;
&lt;p&gt;ctrl+alt+l代码格式化
Setting:
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/17/15397460140526.jpg&quot; alt=&quot;PhpStorm 代码格式化设置&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Live Templates代码片断&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://laracasts.com/series/how-to-be-awesome-in-phpstorm&quot;&gt;https://laracasts.com/series/how-to-be-awesome-in-phpstorm&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;光标跳转&lt;/p&gt;
&lt;p&gt;移动光标到当前所在代码的花括号开始位置 &lt;code&gt;Ctrl + [ Option+Command+[&lt;/code&gt;
移动光标到当前所在代码的花括号结束位置 &lt;code&gt;Ctrl + ] Option+Command+]&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;行处理&lt;/p&gt;
&lt;p&gt;删除光标所在行 或 删除选中的行. &lt;code&gt;Ctrl + Y, Command+delete&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;递进式选择代码块,可选中光标所在的单词或段落，连续按会在原有选中的基础上再扩展选中范围. &lt;code&gt;Ctrl + W , Option+↑&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在当前文件跳转到指定行处(代码报错跳转) &lt;code&gt;Ctrl + G Command+L ⌘+L&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;类处理&lt;/p&gt;
&lt;p&gt;显示当前类的层次结构(继承或实现接口层次结构) &lt;code&gt;Ctrl + H Control + H&lt;/code&gt;
选择可重写的方法(接口方法) &lt;code&gt;Ctrl + O Control + O&lt;/code&gt;
选择可继承的方法 &lt;code&gt;Ctrl + I Control + I&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;根据输入的 类名 查找类文件 &lt;code&gt;Ctrl + N Command+O ⌘+O&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;进入光标所在的方法/变量的接口或是定义出 (预测返回值,详细类型) &lt;code&gt;Ctrl + B或 Ctrl + 左键单击 Command + B 或 Command + 左键单击&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;弹出当前文件结构层，可以在弹出的层上直接输入，进行筛选 &lt;code&gt;Ctrl + F12 Command+F12&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;查找//@todo标签 &lt;code&gt;Alt + 6 Command+6&lt;/code&gt;
显示类中的方法(左下角显示) &lt;code&gt;Alt + 7 Command+7&lt;/code&gt;
显示类中的方法 &lt;code&gt;Alt + 8 Command+8&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;代码自动生成，
如生成对象的 set / get 方法，
构造函数，toString() 等 (get成员属性) &lt;code&gt;Alt + Insert Control+Enter 或 Command+N&lt;/code&gt;
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/17/15397481366192.jpg&quot; alt=&quot;PhpStorm 常用快捷键设置界面&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;代码块&lt;/p&gt;
&lt;p&gt;智能分隔行(左侧小灯泡实现) &lt;code&gt;Ctrl + Enter Option+Enter&lt;/code&gt;
&lt;strong&gt;根据光标所在问题，提供快速修复选择，光标放在的位置不同提示的(左侧小灯泡实现)结果也不同&lt;/strong&gt; &lt;code&gt;Alt + Enter Option+Enter&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;展开代码 &lt;code&gt;Ctrl + +&lt;/code&gt;
折叠代码 &lt;code&gt;Ctrl + -&lt;/code&gt;
选中文本，
逐个往下查找相同文本，并高亮显示 &lt;code&gt;Alt + F3 Command+F&lt;/code&gt;
退回到上一个操作的地方 （必备） &lt;code&gt;Ctrl + Alt + 左方向键 Option+Command+←&lt;/code&gt;
前进到上一个操作的地方 （必备） &lt;code&gt;Ctrl + Alt + 右方向键 Option+Command+→&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;注释
设置中搜索show quick document
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/27/15432880466209.jpg&quot; alt=&quot;PhpStorm 快速文档显示设置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/27/15432880564128.jpg&quot; alt=&quot;PhpStorm 鼠标悬停文档设置&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/27/15432881414343.jpg&quot; alt=&quot;PhpStorm 代码注释文档预览&quot; /&gt;&lt;/p&gt;
&lt;p&gt;鼠标移过将会显示定义时的注释
&lt;code&gt;Ctrl(cmd) + /&lt;/code&gt;，单行注释
&lt;code&gt;Ctrl(cmd) + Shift + /&lt;/code&gt;，多行注释,块注释
&lt;code&gt;/** + Enter&lt;/code&gt;，自动生成注释&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;工作区&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;刷新工作区目录
当有新文件,idea并没有显示就需要手动刷新
&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/11/27/15398345291141.jpg&quot; alt=&quot;PhpStorm Synchronize 工作区刷新按钮&quot; /&gt;
在Save All旁边的按钮Synchronize按钮&lt;code&gt;(Mac)option+command+Y (win)可能是ctrol+alt+Y&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本文内容部分来源:&lt;a href=&quot;https://blog.csdn.net/fenglailea/article/details/53350080?utm_source=copy&quot;&gt;https://blog.csdn.net/fenglailea/article/details/53350080?utm_source=copy&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>前端cdn失效修复</title><link>https://www.motouguai.com/note/frontend-cdn-failure-repair/</link><guid isPermaLink="true">https://www.motouguai.com/note/frontend-cdn-failure-repair/</guid><description>博客出现访问卡死现象,排查一下发现https://cdn.bootcss.com/的访问卡住,导致页面白屏等待资源加载 将https://cdn.bootcss.com/替换为https://cdnjs.cloudflare.com/ajax/libs/</description><pubDate>Tue, 16 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;ul&gt;
&lt;li&gt;博客出现访问卡死现象,排查一下发现&lt;a href=&quot;https://cdn.bootcss.com/%E7%9A%84%E8%AE%BF%E9%97%AE%E5%8D%A1%E4%BD%8F,%E5%AF%BC%E8%87%B4%E9%A1%B5%E9%9D%A2%E7%99%BD%E5%B1%8F%E7%AD%89%E5%BE%85%E8%B5%84%E6%BA%90%E5%8A%A0%E8%BD%BD&quot;&gt;https://cdn.bootcss.com/的访问卡住,导致页面白屏等待资源加载&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396692725137.jpg&quot; alt=&quot;图片&quot; /&gt;&lt;/p&gt;
&lt;p&gt;将&lt;a href=&quot;https://cdn.bootcss.com/&quot;&gt;https://cdn.bootcss.com/&lt;/a&gt;
替换为&lt;a href=&quot;https://cdnjs.cloudflare.com/ajax/libs/&quot;&gt;https://cdnjs.cloudflare.com/ajax/libs/&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>mysql查询设置大小写敏感以及性能(explain)对比</title><link>https://www.motouguai.com/note/mysql-query-sets-case-sensitivity-and-performance-explain-comparison/</link><guid isPermaLink="true">https://www.motouguai.com/note/mysql-query-sets-case-sensitivity-and-performance-explain-comparison/</guid><description>受到 此文 某些似懂非懂话语影响而折腾的笔记 解决方法: 查询时加上binaryexplain 分析 sql语句其中type有变动(sk已加上索引) type值解析 而不加binary 不区分大小写时 查询时强制二进制对比，尤其不好，这会让你代码中多出很多判断，且还有可能被绕过。至于直接使用二进制字段，mysql不会将它当成字符来处理，我觉得也可能存在问题。</description><pubDate>Tue, 16 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;受到 &lt;a href=&quot;https://segmentfault.com/q/1010000005675226&quot;&gt;此文&lt;/a&gt; 某些似懂非懂话语影响而折腾的笔记&lt;/p&gt;
&lt;p&gt;解决方法:&lt;/p&gt;
&lt;h3&gt;查询时加上&lt;code&gt;binary&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;explain 分析 sql语句
其中type有变动(sk已加上索引) &lt;a href=&quot;https://blog.csdn.net/dennis211/article/details/78170079&quot;&gt;type值解析&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396619365909.jpg&quot; alt=&quot;使用 binary 查询时的第一组 EXPLAIN 结果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396619512701.jpg&quot; alt=&quot;使用 binary 查询时的第二组 EXPLAIN 结果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;而不加&lt;code&gt;binary&lt;/code&gt; 不区分大小写时&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396620016535.jpg&quot; alt=&quot;不区分大小写查询时的 EXPLAIN 结果&quot; /&gt;&lt;/p&gt;
&lt;p&gt;查询时强制二进制对比，尤其不好，这会让你代码中多出很多判断，且还有可能被绕过。至于直接使用二进制字段，mysql不会将它当成字符来处理，我觉得也可能存在问题。&lt;/p&gt;
&lt;h3&gt;字段建立时指定字符类型&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/sonofelice/p/6432986.html&quot;&gt;点我查看 建立时的字符类型&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396624852228.jpg&quot; alt=&quot;MySQL 字段字符集与排序规则设置&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;使用&lt;code&gt;utf8_bin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;select * from api_key where sk = &apos;Gsxg583i+JhD4nHFCroeLKlMpUAI0XV9Rzjf6YqO_1Svy7QZkmw2PB&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Select 语句可以区分大小写
执行效率:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;explain select * from api_key where sk = &apos;GSxg583i+JhD4nHFCroeLKlMpUAI0XV9Rzjf6YqO_1Svy7QZkmw2PB&apos;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396630432653.jpg&quot; alt=&quot;utf8_bin 字段查询的 EXPLAIN 结果&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用&lt;code&gt;BINARY&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396631279214.jpg&quot; alt=&quot;MySQL BINARY 字段定义示例&quot; /&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`select * from api_key where sk = &apos;Gsxg583i+JhD4nHFCroeLKlMpUAI0XV9Rzjf6YqO_1Svy7QZkmw2PB&apos;`
Select 语句可以区分大小写
执行效率:
`explain select * from api_key where sk = &apos;GSxg583i+JhD4nHFCroeLKlMpUAI0XV9Rzjf6YqO_1Svy7QZkmw2PB&apos;`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/markdown/2018/10/16/15396633217279.jpg&quot; alt=&quot;BINARY 字段查询的 EXPLAIN 结果&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;数据库创建时修改&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cnblogs.com/paul8339/p/6932138.html&quot;&gt;方式1&lt;/a&gt;
&lt;a href=&quot;https://bbs.csdn.net/topics/340204174&quot;&gt;方式2&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;laravel 数据库迁移解决方案&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;public function up()
{
    Schema::create(&apos;api_key&apos;, function (Blueprint $table) {

        //一堆建表语句
    });
    //创建表成功后添加大小写敏感
    DB::statement(&quot;alter table api_key modify column ak varchar(255)  BINARY DEFAULT &apos;&apos; NOT NULL COMMENT &apos;as&apos;&quot;);
    DB::statement(&quot;alter table api_key modify column sk varchar(255)  BINARY DEFAULT &apos;&apos; NOT NULL COMMENT &apos;as&apos;&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;最终得出&lt;/h3&gt;
&lt;p&gt;以上更改其实本质上也是把collatioin(校对)模式改成二进制校对，实现大小写敏感。&lt;/p&gt;
&lt;p&gt;索引长度在判断大小写时会增加1,但是type会变成ref;&lt;/p&gt;
&lt;p&gt;附给细心同学的懒人链接:&lt;a href=&quot;https://www.cnblogs.com/lukexwang/articles/7060950.html&quot;&gt;key_len&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;参考资料:
&lt;a href=&quot;https://www.cnblogs.com/sonofelice/p/6432986.html&quot;&gt;https://www.cnblogs.com/sonofelice/p/6432986.html&lt;/a&gt;
&lt;a href=&quot;http://cevin.net/archives/%E8%AE%A9mysql%E6%9F%A5%E8%AF%A2%E5%8C%BA%E5%88%86%E5%A4%A7%E5%B0%8F%E5%86%99.html&quot;&gt;http://cevin.net/archives/让mysql查询区分大小写.html&lt;/a&gt;
&lt;a href=&quot;https://blog.csdn.net/dennis211/article/details/78170079&quot;&gt;https://blog.csdn.net/dennis211/article/details/78170079&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/yuyue2014/p/3700531.html&quot;&gt;https://www.cnblogs.com/yuyue2014/p/3700531.html&lt;/a&gt;
&lt;a href=&quot;https://www.cnblogs.com/clphp/p/5403215.html&quot;&gt;https://www.cnblogs.com/clphp/p/5403215.html&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>php二维数组数据指定键唯一合并</title><link>https://www.motouguai.com/technology-php/php-twodimensional-array-data-specified-key-unique-merge/</link><guid isPermaLink="true">https://www.motouguai.com/technology-php/php-twodimensional-array-data-specified-key-unique-merge/</guid><description>例子: 12345678910111213141516171819202122232425262728293031323334353637383940414243444546array:11 [ 0 =&amp;gt; array:2 [ &quot;publicadtype&quot; =&amp;gt; &quot;h5-zmiti&quot; &quot;num&quot; =&amp;gt; 16 ] 1 =&amp;gt; array:2</description><pubDate>Mon, 15 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;例子:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;array:11 [
  0 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;h5-zmiti&quot;
    &quot;num&quot; =&amp;gt; 16
  ]
  1 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;图片-zmiti&quot;
    &quot;num&quot; =&amp;gt; 88
  ]
  2 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;视频-zmiti&quot;
    &quot;num&quot; =&amp;gt; 13
  ]
  3 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;音频-zmiti&quot;
    &quot;num&quot; =&amp;gt; 30
  ]
  4 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;视频-zmiti&quot;
    &quot;notaudit&quot; =&amp;gt; 4
  ]
  5 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;h5-zmiti&quot;
    &quot;trial&quot; =&amp;gt; 16
  ]
  6 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;图片-zmiti&quot;
    &quot;trial&quot; =&amp;gt; 88
  ]
  7 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;视频-zmiti&quot;
    &quot;trial&quot; =&amp;gt; 8
  ]
  8 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;音频-zmiti&quot;
    &quot;trial&quot; =&amp;gt; 27
  ]
  9 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;视频-zmiti&quot;
    &quot;initialfailure&quot; =&amp;gt; 1
  ]
  10 =&amp;gt; array:2 [
    &quot;publicadtype&quot; =&amp;gt; &quot;音频-zmiti&quot;
    &quot;thefinal&quot; =&amp;gt; 3
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;将此数组变为:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;array:4 [
  0 =&amp;gt; array:3 [
    &quot;publicadtype&quot; =&amp;gt; &quot;h5-zmiti&quot;
    &quot;num&quot; =&amp;gt; 16
    &quot;trial&quot; =&amp;gt; 16
  ]
  1 =&amp;gt; array:3 [
    &quot;publicadtype&quot; =&amp;gt; &quot;图片-zmiti&quot;
    &quot;num&quot; =&amp;gt; 88
    &quot;trial&quot; =&amp;gt; 88
  ]
  2 =&amp;gt; array:5 [
    &quot;publicadtype&quot; =&amp;gt; &quot;视频-zmiti&quot;
    &quot;num&quot; =&amp;gt; 13
    &quot;notaudit&quot; =&amp;gt; 4
    &quot;trial&quot; =&amp;gt; 8
    &quot;initialfailure&quot; =&amp;gt; 1
  ]
  3 =&amp;gt; &amp;amp; array:4 [
    &quot;publicadtype&quot; =&amp;gt; &quot;音频-zmiti&quot;
    &quot;num&quot; =&amp;gt; 30
    &quot;trial&quot; =&amp;gt; 27
    &quot;thefinal&quot; =&amp;gt; 3
  ]
]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;可用代码:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$json = &apos;[{&quot;publicadtype&quot;:&quot;h5-zmiti&quot;,&quot;num&quot;:16},{&quot;publicadtype&quot;:&quot;\u56fe\u7247-zmiti&quot;,&quot;num&quot;:88},{&quot;publicadtype&quot;:&quot;\u89c6\u9891-zmiti&quot;,&quot;num&quot;:13},{&quot;publicadtype&quot;:&quot;\u97f3\u9891-zmiti&quot;,&quot;num&quot;:30},{&quot;publicadtype&quot;:&quot;\u89c6\u9891-zmiti&quot;,&quot;notaudit&quot;:4},{&quot;publicadtype&quot;:&quot;h5-zmiti&quot;,&quot;trial&quot;:16},{&quot;publicadtype&quot;:&quot;\u56fe\u7247-zmiti&quot;,&quot;trial&quot;:88},{&quot;publicadtype&quot;:&quot;\u89c6\u9891-zmiti&quot;,&quot;trial&quot;:8},{&quot;publicadtype&quot;:&quot;\u97f3\u9891-zmiti&quot;,&quot;trial&quot;:27},{&quot;publicadtype&quot;:&quot;\u89c6\u9891-zmiti&quot;,&quot;initialfailure&quot;:1},{&quot;publicadtype&quot;:&quot;\u97f3\u9891-zmiti&quot;,&quot;thefinal&quot;:3}]&apos;;
$data = json_decode($json, true);

foreach ($data as $nk =&amp;gt; &amp;amp;$nv) {
    foreach ($data as $nnk =&amp;gt; $nnv) {
        if ($nk !== $nnk) {
            if (in_array($nv[&apos;publicadtype&apos;], $nnv)) {
                $nv = array_merge($nv, $nnv);
                if ($nnk !== $nk) {
                    unset($data[$nnk]);
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ps:此代码有一个重复赋值找出修改方法吧&lt;/p&gt;
&lt;p&gt;数组复杂处理常见的引用符号,加上后有些重复处理和赋值会直接操作原有数组.&lt;/p&gt;
</content:encoded></item><item><title>编码习惯-2019.06.03</title><link>https://www.motouguai.com/note/coding-habit-20190603/</link><guid isPermaLink="true">https://www.motouguai.com/note/coding-habit-20190603/</guid><description>本文档长期不定时更新 在使用get()或者select() 查询列表时,要么分页,要么limit限制最大长度 在使用return 时尽量只有一个return 方便查阅; 在编写类时,注意单一职责; 变量尽量在有必要提前存在时才声明 php是弱类型语言,对数据记得做类型校验 对方法参数做类型约束 数据库状态或数字代表含义的, 放在配置文件然后调取语义化配置使用</description><pubDate>Wed, 10 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;本文档长期不定时更新&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;在使用get()或者select() 查询列表时,要么分页,要么limit限制最大长度&lt;/li&gt;
&lt;li&gt;在使用return 时尽量只有一个return 方便查阅;&lt;/li&gt;
&lt;li&gt;在编写类时,注意单一职责;&lt;/li&gt;
&lt;li&gt;变量尽量在有必要提前存在时才声明&lt;/li&gt;
&lt;li&gt;php是弱类型语言,对数据记得做类型校验&lt;/li&gt;
&lt;li&gt;对方法参数做类型约束&lt;/li&gt;
&lt;li&gt;数据库状态或数字代表含义的, 放在配置文件然后调取语义化配置使用,方便查阅&lt;/li&gt;
&lt;li&gt;不使用is_系列函数,使用全等替换&lt;/li&gt;
&lt;li&gt;减少使用= = 而去使用=== &lt;a href=&quot;http://www.codeceo.com/article/juggling-hashes-with-your-eyes-closed-in-php.html&quot;&gt;案例&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;在c中i++只需要一条cpu指令, 一直以为$i++的效率很高, 但是我看到的框架(比如tp)都没用使用$i++, 而是使用$i += 1, 在php中$i++需要4条opcodes&lt;/li&gt;
&lt;li&gt;编写或调用缓存时 注意:命中 (Hit) - 一个缓存的命中，指的是当调用类库使用「键」在请求一个缓存项的时候，在缓存池里能找到对应的缓存项，并且此缓存项还未过期，并且此数据不会因为任何原因出现错误。调用类库 应该 确保先验证下 isHit() 有命中后才调用 get() 获取数据。 &lt;a href=&quot;https://learnku.com/docs/psr/psr-6-cache/1614&quot;&gt;参考&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;前后端分离返回数据的参数键命名分隔时,尽量使用下划线分隔&lt;/li&gt;
&lt;li&gt;在laravel模型通过属性获取模型关联数据数据如果这个字段有可能不存在的 使用isset判断 或使用 ?? ‘’&lt;/li&gt;
&lt;li&gt;编写权限或者状态时预留方法 返回可用账户的where组合&lt;/li&gt;
&lt;li&gt;按照单一职责原则，一个类只应该关心自己的逻辑，当出现问题的时候，如果不是当前类该处理的，我们就应该抛出而不是消化。&lt;/li&gt;
&lt;li&gt;业务异常与运行时异常要区分开&lt;/li&gt;
&lt;li&gt;一个类只干自己相关的事情，比如通知类不要去关心 SMTP 如何构造。&lt;/li&gt;
&lt;li&gt;一个方法只干一件事儿，如何定义呢？当你给方法起名的时候纠结了，那你的方法设计得就有问题了，getUserById，getUsers 这些肯定就是只干了一件事儿。&lt;/li&gt;
&lt;li&gt;命名要见名知义，动名词格式命名。少用 info，data 这类无意义词，比如 getUserInfo 完全可以叫 getUser。getOrdersData，getOrdersList 也完全可以写为 getOrders。&lt;/li&gt;
&lt;li&gt;一个方法尽量不要超过 30 行；&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>利用PHP将HTML页面生成PDF文档</title><link>https://www.motouguai.com/mo-ren-fen-lei/generate-pdf-documents-from-html-pages-using-php/</link><guid isPermaLink="true">https://www.motouguai.com/mo-ren-fen-lei/generate-pdf-documents-from-html-pages-using-php/</guid><description>标签（空格分隔）： php特殊处理 使用TCPDF第三方类库进行生成githup下载地址：https://github.com/tecnickcom/tcpdf官方下载地址：http://sourceforge.net/projects/tcpdf/ 核心代码： 12345678910111213141516171819202122232425public </description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： php特殊处理&lt;/p&gt;
&lt;h2&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/usr/uploads/2018/07/1138046482.jpg&quot; alt=&quot;pdf.jpg&quot; /&gt;&lt;/h2&gt;
&lt;p&gt;使用&lt;code&gt;TCPDF&lt;/code&gt;第三方类库进行生成
githup下载地址：&lt;a href=&quot;https://github.com/tecnickcom/tcpdf&quot;&gt;https://github.com/tecnickcom/tcpdf&lt;/a&gt;
官方下载地址：&lt;a href=&quot;http://sourceforge.net/projects/tcpdf/&quot;&gt;http://sourceforge.net/projects/tcpdf/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;核心代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static function writePdf($content)
    {
        $pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, &apos;UTF-8&apos;, false);
        $pdf-&amp;gt;SetCreator(PDF_CREATOR);

        $pdf-&amp;gt;SetHeaderData(&quot;logo.jpg&quot;, 70, &apos;wanglibao Agreement&apos; . &apos;&apos;, &apos;&apos;);
        $pdf-&amp;gt;SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
        $pdf-&amp;gt;SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
        $pdf-&amp;gt;SetHeaderMargin(PDF_MARGIN_HEADER);
        $pdf-&amp;gt;SetFooterMargin(PDF_MARGIN_FOOTER);
        $pdf-&amp;gt;SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
        $pdf-&amp;gt;setImageScale(PDF_IMAGE_SCALE_RATIO);
        $pdf-&amp;gt;AddPage();
        $pdf-&amp;gt;setPageMark();
        $pdf-&amp;gt;SetFont(&apos;stsongstdlight&apos;, &apos;&apos;, 13);
        $title = &amp;lt;&amp;lt;&amp;lt;EOD
&amp;lt;h2&amp;gt;标题&amp;lt;/h2&amp;gt;
EOD;

        $pdf-&amp;gt;writeHTML($content, true, false, false, false, &apos;&apos;);
//         $pdf-&amp;gt;writeHTML($content, true, 0, true, true);
//         $pdf-&amp;gt;writeHTMLCell(0, 0, &apos;&apos;, &apos;&apos;, $content, 0, 1, 0, true, &apos;C&apos;, true);
        $pdf-&amp;gt;lastPage();
        $pdf-&amp;gt;Output(date(&apos;Y-m-d&apos;) . &apos;.pdf&apos;, &apos;I&apos;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;汉子出现乱码解决办法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;设置
&lt;code&gt;$pdf-&amp;gt;setHeaderFont(array(PDF_FONT_NAME_MAIN,&apos;&apos;,PDF_FONT_SIZE_MAIN);&lt;/code&gt;
其中&lt;code&gt;PDF_FONT_NAME_MAIN&lt;/code&gt;就是设置头部的字体编码。
将&lt;code&gt;PDF_FONT_NAME_MAIN&lt;/code&gt;设置为 &lt;code&gt;msungstdlight&lt;/code&gt;。页面中的字体：在 &lt;code&gt;$pdf-&amp;gt;writeHtml()&lt;/code&gt; ;或者&lt;code&gt;$pdf-&amp;gt;Cell()&lt;/code&gt;;等之前设置 &lt;code&gt;$pdf-&amp;gt;SetFont(msungstdlight,&apos;&apos;, 字体大小)&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;汉字不出现乱码的代码如下：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;?php
//引入tcpdf文件
	require_once(&apos;./TCPDF-master/tcpdf.php&apos;);
//实例化
$pdf = new TCPDF(&apos;P&apos;, &apos;mm&apos;, &apos;A4&apos;, true, &apos;UTF-8&apos;, false);
// 设置文档信息
$pdf-&amp;gt;SetCreator(&apos;哈喽&apos;);
$pdf-&amp;gt;SetAuthor(&apos;作者&apos;);
$pdf-&amp;gt;SetTitle(&apos;哈哈哈哈哈哈&apos;);
$pdf-&amp;gt;SetSubject(&apos;TCPDF Tutorial&apos;);
$pdf-&amp;gt;SetKeywords(&apos;TCPDF, PDF, PHP&apos;);
// 设置页眉和页脚信息
$pdf-&amp;gt;SetHeaderData(&apos;logo.png&apos;, 10, &apos;kkkkkk&apos;, &apos;就是做个PDF&apos;,
      array(0,64,255), array(0,64,128));
$pdf-&amp;gt;setFooterData(array(0,64,0), array(0,64,128));
// 设置页眉和页脚字体
$pdf-&amp;gt;setHeaderFont(Array(&apos;stsongstdlight&apos;, &apos;&apos;, &apos;10&apos;));
$pdf-&amp;gt;setFooterFont(Array(&apos;helvetica&apos;, &apos;&apos;, &apos;8&apos;));
// 设置默认等宽字体
$pdf-&amp;gt;SetDefaultMonospacedFont(&apos;courier&apos;);
// 设置间距
$pdf-&amp;gt;SetMargins(15, 27, 15);
$pdf-&amp;gt;SetHeaderMargin(5);
$pdf-&amp;gt;SetFooterMargin(10);
// 设置分页
$pdf-&amp;gt;SetAutoPageBreak(TRUE, 25);
// set image scale factor
$pdf-&amp;gt;setImageScale(1.25);
// set default font subsetting mode
$pdf-&amp;gt;setFontSubsetting(true);
//设置字体
$pdf-&amp;gt;SetFont(&apos;stsongstdlight&apos;, &apos;&apos;, 14);
$pdf-&amp;gt;AddPage();
$str1 = &quot;
	&amp;lt;table border=\&quot;1\&quot;&amp;gt;
		&amp;lt;tr&amp;gt;
			&amp;lt;td&amp;gt;哈哈&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;123&amp;lt;/td&amp;gt;
			&amp;lt;td&amp;gt;123&amp;lt;/td&amp;gt;
		&amp;lt;/tr&amp;gt;
	&amp;lt;/table&amp;gt;
&quot;;
$pdf-&amp;gt;WriteHTML($str1,&apos;&apos;, 0, &apos;L&apos;, true, 0, false, false, 0);
//输出PDF
$pdf-&amp;gt;Output(&apos;t.pdf&apos;, &apos;I&apos;);
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>rtmp流媒体 nginx服务端搭建</title><link>https://www.motouguai.com/mo-ren-fen-lei/rtmp-streaming-nginx-server-build/</link><guid isPermaLink="true">https://www.motouguai.com/mo-ren-fen-lei/rtmp-streaming-nginx-server-build/</guid><description>标签（空格分隔）： 直播 mkdir nginx 切换到nginx目录，下载压缩包并解压到当前工作目录： wget http://nginx.org/download/nginx-1.12.1.tar.gz tar -zxvf nginx-1.12.1.tar.gz 安装依赖的的库： sudo apt-get install libssl-dev libpc</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： 直播&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;mkdir nginx&lt;/p&gt;
&lt;p&gt;切换到nginx目录，下载压缩包并解压到当前工作目录：&lt;/p&gt;
&lt;p&gt;wget &lt;a href=&quot;http://nginx.org/download/nginx-1.12.1.tar.gz&quot;&gt;http://nginx.org/download/nginx-1.12.1.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;tar -zxvf nginx-1.12.1.tar.gz&lt;/p&gt;
&lt;p&gt;安装依赖的的库：&lt;/p&gt;
&lt;p&gt;sudo apt-get install libssl-dev libpcre3-dev zlib1g-dev&lt;/p&gt;
&lt;p&gt;下载rtmp模块，生成目录nginx-rtmp-module：&lt;/p&gt;
&lt;p&gt;git clone &lt;a href=&quot;https://github.com/arut/nginx-rtmp-module.git&quot;&gt;https://github.com/arut/nginx-rtmp-module.git&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;切换到nginx-1.12.1目录，执行（如果想build调试版本的话，要添加–with-debug）：&lt;/p&gt;
&lt;p&gt;./configure –add-module=/home/sunrayme/nginx/nginx-rtmp-module
make&lt;/p&gt;
&lt;p&gt;sudo make install&lt;/p&gt;
&lt;p&gt;运行nginx：&lt;/p&gt;
&lt;p&gt;sudo /usr/local/nginx/sbin/nginx&lt;/p&gt;
&lt;p&gt;ffmpeg -f dshow -i video=”BisonCam, NB Pro”:audio=”麦克风 (Realtek High Definition Audio)” -vcodec libx264 -acodec copy -preset:v ultrafast -tune:v zerolatency -f flv “rtmp://p855c26b6.live.126.net/live/685f6451704349a8bed4489f170d4084?wsSecret=1e0357b0ce7e101ac0613396148ae2b4&amp;amp;wsTime=1523430887”&lt;/p&gt;
&lt;p&gt;netstat -ntlp 查看端口占用&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}

rtmp {

    server {

        listen 1935;  #监听的端口

        chunk_size 4000;

	application myapp {
            live on;
         }
        application hls {  #rtmp推流请求路径
            live on;
            hls on;
            hls_path /tmp/hls;
	    hls_fragment 3s;
        }
    }
}
http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  &apos;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &apos;
    #                  &apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;
    #                  &apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;;

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;


    server {
        listen       8080;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location /state {
            rtmp_stat all;
	    rtmp_stat_stylesheet stat.xsl;
        }
	location /stat.xsl {
	    root /vagrant_date/nginx-rtmp-module-master;
	}
    }

    server {
        listen       81;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        #加入hls支持
        location /hls {
            types {
                application/vnd.apple.mpegurl m3u8;
                #或 application/x-mpegURL
                video/mp2t ts;
            }
            alias /tmp/hls;  #视频流文件目录(自己创建)
            expires -1;
            add_header Cache-Control no-cache;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        # proxy the PHP scripts to Apache listening on 127.0.0.1:80
        #
        #location ~ \.php$ {
        #    proxy_pass   http://127.0.0.1;
        #}

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #    root           html;
        #    fastcgi_pass   127.0.0.1:9000;
        #    fastcgi_index  index.php;
        #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
        #    include        fastcgi_params;
        #}

        # deny access to .htaccess files, if Apache&apos;s document root
        # concurs with nginx&apos;s one
        #
        #location ~ /\.ht {
        #    deny  all;
        #}
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置文件验证&lt;/p&gt;
&lt;p&gt;/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf&lt;/p&gt;
&lt;p&gt;ffmpeg -f dshow -i video=”BisonCam, NB Pro”:audio=”麦克风 (Realtek High Definition Audio)” -vcodec libx264 -acodec copy -preset:v ultrafast -tune:v zerolatency -f flv “rtmp://192.168.1.113/live live=1”&lt;/p&gt;
&lt;p&gt;rtmp://192.168.1.113:1935/hls/test
rtmp://192.168.1.113:1935/myapp/test
hls&lt;/p&gt;
&lt;p&gt;加上mp4flv播放和清缓存&lt;/p&gt;
&lt;p&gt;./configure –with-http_ssl_module –add-module=../nginx-rtmp-module –with-http_v2_module –with-http_ssl_module –with-http_sub_module –with-http_stub_status_module –with-http_gzip_static_module –with-pcre&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;./configure --prefix=/usr/local/nginx/ --add-module=../nginx-rtmp-module --add-module=../ngx_cache_purge-master --with-http_stub_status_module --with-http_ssl_module --with-http_sub_module --with-http_gzip_static_module --with-http_mp4_module --with-http_flv_module
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;yum -y install pcre-devel openssl openssl-devel&lt;/p&gt;
&lt;p&gt;有时候，我们需要单独安装nginx，来处理大量的下载请求。单独在Centos5安装nginx遇到的rewrite和HTTP cache错误解决办法：&lt;/p&gt;
&lt;p&gt;wget &lt;a href=&quot;http://nginx.org/download/nginx-0.8.33.tar.gz&quot;&gt;http://nginx.org/download/nginx-0.8.33.tar.gz&lt;/a&gt;
tar -zxvf nginx-0.8.33.tar.gz
cd nginx-0.8.33
./configure –prefix=/usr/local/nginx&lt;/p&gt;
&lt;p&gt;安装Nginx时报错&lt;/p&gt;
&lt;p&gt;./configure: error: the HTTP rewrite module requires the PCRE library.&lt;/p&gt;
&lt;p&gt;安装pcre-devel解决问题
yum -y install pcre-devel&lt;/p&gt;
&lt;p&gt;错误提示：./configure: error: the HTTP cache module requires md5 functions
from OpenSSL library. You can either disable the module by using
–without-http-cache option, or install the OpenSSL library into the system,
or build the OpenSSL library statically from the source with nginx by using
–with-http_ssl_module –with-openssl=options.&lt;/p&gt;
&lt;p&gt;解决办法：&lt;/p&gt;
&lt;p&gt;yum -y install openssl openssl-devel&lt;/p&gt;
&lt;p&gt;总结：&lt;/p&gt;
&lt;p&gt;yum -y install pcre-devel openssl openssl-devel&lt;/p&gt;
&lt;p&gt;./configure –prefix=/usr/local/nginx&lt;/p&gt;
&lt;p&gt;make&lt;/p&gt;
&lt;p&gt;make install&lt;/p&gt;
&lt;p&gt;昌书电脑安装记录&lt;/p&gt;
&lt;p&gt;nginx path prefix: “/usr/local/nginx/“
nginx binary file: “/usr/local/nginx//sbin/nginx”
nginx modules path: “/usr/local/nginx//modules”
nginx configuration prefix: “/usr/local/nginx//conf”
nginx configuration file: “/usr/local/nginx//conf/nginx.conf”
nginx pid file: “/usr/local/nginx//logs/nginx.pid”
nginx error log file: “/usr/local/nginx//logs/error.log”
nginx http access log file: “/usr/local/nginx//logs/access.log”
nginx http client request body temporary files: “client_body_temp”
nginx http proxy temporary files: “proxy_temp”
nginx http fastcgi temporary files: “fastcgi_temp”
nginx http uwsgi temporary files: “uwsgi_temp”
nginx http scgi temporary files: “scgi_temp”&lt;/p&gt;
&lt;p&gt;编译时出现 set but not used [-Werror=unused-but-set-variable] 问题的解决办法：
找到对应目录(nginx中)中的Makefile文件，找到 -Werror 字段，去掉-Werror，重新编译，则问题解决&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rtmp://p855c26b6.live.126.net/live/685f6451704349a8bed4489f170d4084?wsSecret=aec4eda8a73a12c2dd525319608bf533&amp;amp;wsTime=1523520333


rtmp://192.168.1.119:1935/myapp/test
rtmp://192.168.1.119:1935/myapp/test

rtmp://192.168.1.119:1935/hls/test
http://111.231.138.185:81/hls/test


#user  nobody;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;worker_processes 2;&lt;/p&gt;
&lt;p&gt;#error_log logs/error.log;&lt;/p&gt;
&lt;p&gt;#error_log logs/error.log notice;&lt;/p&gt;
&lt;p&gt;#error_log logs/error.log info;&lt;/p&gt;
&lt;p&gt;#pid logs/nginx.pid;&lt;/p&gt;
&lt;p&gt;events {
worker_connections 1024;
}&lt;/p&gt;
&lt;p&gt;http {
include mime.types;
default_type application/octet-stream;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#log_format  main  &apos;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &apos;
#                  &apos;$status $body_bytes_sent &quot;$http_referer&quot; &apos;
#                  &apos;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&apos;;

#access_log  logs/access.log  main;

sendfile        on;
#tcp_nopush     on;

#keepalive_timeout  0;
keepalive_timeout  65;

#gzip  on;


server {
    listen       8080;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    location /state {
        rtmp_stat all;
        rtmp_stat_stylesheet stat.xsl;
    }
    location /stat.xsl {
        root /vagrant_date/nginx-rtmp-module-master;
    }
}

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;

    #access_log  logs/host.access.log  main;

    #加入hls支持
    location /hls {
        types {
            application/vnd.apple.mpegurl m3u8;
            #或 application/x-mpegURL
            video/mp2t ts;
        }
        alias /tmp/hls;  #视频流文件目录(自己创建)
        expires -1;
        add_header Cache-Control no-cache;
    }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;rtmp_auto_push on; #因为Nginx可能开启多个子进程，这个选项表示推流时，媒体流会发布到多个子进程&lt;/p&gt;
&lt;p&gt;rtmp {&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;server {

    listen 1935;  #监听的端口

    chunk_size 4000;

    application myapp {
            live on;
    }
    application hls {  #rtmp推流请求路径
        live on;
        hls on;
        hls_path /tmp/hls;
        hls_fragment 3s; #每个视频切片的时长
        hls_playlist_length 0s; #总共可以回看的事件，这里设置的是1分钟。
        hls_continuous on; #连续模式。
        hls_cleanup on;    #对多余的切片进行删除。
        hls_nested on;     #嵌套模式。
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;}&lt;/p&gt;
</content:encoded></item><item><title>Docker配置开发环境常用命令_参数详解(1</title><link>https://www.motouguai.com/note/docker-configuration-development-environment-commonly-used-commands-parameters-detailed-1/</link><guid isPermaLink="true">https://www.motouguai.com/note/docker-configuration-development-environment-commonly-used-commands-parameters-detailed-1/</guid><description>Docker配置开发环境常用命令_参数详解标签（空格分隔）： docker 在下载image后我们需要一个可以运行项目的环境</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Docker配置开发环境常用命令_参数详解&lt;/h1&gt;
&lt;p&gt;标签（空格分隔）： docker&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;在下载image后我们需要一个可以运行项目的环境&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;使用下载的image运行容器&lt;/h4&gt;
&lt;p&gt;命令：&lt;code&gt;docker run&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;当利用 docker run 来创建容器时，Docker 在后台运行的标准操作包括：

检查本地是否存在指定的镜像，不存在就从公有仓库下载
利用镜像创建并启动一个容器
分配一个文件系统，并在只读的镜像层外面挂载一层可读写层
从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
从地址池配置一个 ip 地址给容器
执行用户指定的应用程序
执行完毕后容器被终止
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;用法&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run [OPTIONS] IMAGE [COMMAND] [ARG...]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Options&lt;/em&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;&lt;code&gt;--add-host&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;添加一个自定义的主机IP映射（主持人：IP）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--attach , -a&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;attach到stdin stdout或stderr，&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--blkio-weight&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;块IO（相对量），10和1000之间，或0禁用（默认为0）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--blkio-weight-device&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;块IO量（相对装置重量）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cap-add&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;添加Linux的功能&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cap-drop&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Linux的能力下降&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cgroup-parent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;可选的父容器的C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cidfile&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;写容器的ID文件&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-count&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;CPU数量（Windows）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-percent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;CPU的百分比（Windows）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-period&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;限制CPU CFS（完全公平调度器）期&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-quota&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;限制CPU CFS（完全公平调度器）定额&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-rt-period&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.25/&quot;&gt;API 1.25&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;限制CPU的实时周期在微秒&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-rt-runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.25/&quot;&gt;API 1.25&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;限制CPU的实时运行在微秒&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpu-shares , -c&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;CPU份额（相对量）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.25/&quot;&gt;API 1.25&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CPU数量&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpuset-cpus&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;这允许CPU执行（0，0）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpuset-mems&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;MEMS中允许执行（0，0）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--detach , -d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;运行容器的背景和打印容器ID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--detach-keys&lt;/code&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;&lt;code&gt;--device&lt;/code&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;&lt;code&gt;--device-cgroup-rule&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;添加一条规则，允许设备列表的C&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--device-read-bps&lt;/code&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;&lt;code&gt;--device-read-iops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;限制读取率（IO每秒）从设备&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--device-write-bps&lt;/code&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;&lt;code&gt;--device-write-iops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;限制写速率（IO每秒）的一种装置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--disable-content-trust&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;跳过图像验证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dns&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;设置自定义的DNS服务器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dns-opt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;设置DNS选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dns-option&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;设置DNS选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dns-search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;设置自定义DNS搜索域&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--entrypoint&lt;/code&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;&lt;code&gt;--env , -e&lt;/code&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;&lt;code&gt;--env-file&lt;/code&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;&lt;code&gt;--expose&lt;/code&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;&lt;code&gt;--group-add&lt;/code&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;&lt;code&gt;--health-cmd&lt;/code&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;&lt;code&gt;--health-interval&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;之间运行的检查时间（MS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--health-retries&lt;/code&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;&lt;code&gt;--health-start-period&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.29/&quot;&gt;API 1.29&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;对于容器初始化之前开始倒计时起始期健康重试（MS&lt;/td&gt;
&lt;td&gt;的&lt;/td&gt;
&lt;td&gt;M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--health-timeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;允许一个检查运行的最大时间（MS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--help&lt;/code&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;&lt;code&gt;--hostname , -h&lt;/code&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;&lt;code&gt;--init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.25/&quot;&gt;API 1.25&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;&lt;code&gt;--interactive , -i&lt;/code&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;&lt;code&gt;--io-maxbandwidth&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;的驱动系统的最大IO带宽限制（仅适用于Windows）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--io-maxiops&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;对系统驱动Maximum IOps极限（Windows）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--ip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;IPv4地址（例如，172.30.100.104）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--ip6&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;IPv6的地址（例如，2001：db8：：33）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--ipc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;IPC模式使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--isolation&lt;/code&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;&lt;code&gt;--kernel-memory&lt;/code&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;&lt;code&gt;--label , -l&lt;/code&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;&lt;code&gt;--label-file&lt;/code&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;&lt;code&gt;--link&lt;/code&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;&lt;code&gt;--link-local-ip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;集装箱IPv4和IPv6链路本地地址&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--log-driver&lt;/code&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;&lt;code&gt;--log-opt&lt;/code&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;&lt;code&gt;--mac-address&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;集装箱的MAC地址（例如92：D0：c6:0a：29:33）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--memory , -m&lt;/code&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;&lt;code&gt;--memory-reservation&lt;/code&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;&lt;code&gt;--memory-swap&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;互换限额等于内存和交换：&apos; 1 &apos;使无限的互换&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--memory-swappiness&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;调容器内存swappiness（0到100）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--mount&lt;/code&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;&lt;code&gt;--name&lt;/code&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;&lt;code&gt;--net&lt;/code&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;&lt;code&gt;--net-alias&lt;/code&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;&lt;code&gt;--network&lt;/code&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;&lt;code&gt;--network-alias&lt;/code&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;&lt;code&gt;--no-healthcheck&lt;/code&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;&lt;code&gt;--oom-kill-disable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;禁用OOM Killer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--oom-score-adj&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;调主机的OOM的偏好（1000到1000）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--pid&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;PID命名空间的使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--pids-limit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;调整PID（集1容器极限无限）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--platform&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file&quot;&gt;实验（守护）&lt;/a&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.32/&quot;&gt;API 1.32&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;&lt;code&gt;--privileged&lt;/code&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;&lt;code&gt;--publish , -p&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Publish a container’s port(s) to the host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--publish-all , -P&lt;/code&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;&lt;code&gt;--read-only&lt;/code&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;&lt;code&gt;--restart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;no&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;重启政策适用在集装箱出口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--rm&lt;/code&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;&lt;code&gt;--runtime&lt;/code&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;&lt;code&gt;--security-opt&lt;/code&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;&lt;code&gt;--shm-size&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;大小/ dev / shm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--sig-proxy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;代理接收到的信号的过程&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--stop-signal&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;SIGTERM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;信号停止一个容器&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--stop-timeout&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://docs.docker.com/engine/api/v1.25/&quot;&gt;API 1.25&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&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;&lt;code&gt;--storage-opt&lt;/code&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;&lt;code&gt;--sysctl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;sysctl选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--tmpfs&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;安装tmpfs目录&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--tty , -t&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;分配给伪tty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--ulimit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;ulimit选项&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--user , -u&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Username or UID (format: &amp;lt;name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--userns&lt;/code&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;&lt;code&gt;--uts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;UTS命名空间的使用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--volume , -v&lt;/code&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;&lt;code&gt;--volume-driver&lt;/code&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;&lt;code&gt;--volumes-from&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;山卷从指定的容器（S）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--workdir , -w&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;容器内的工作目录&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre&gt;&lt;code&gt;------------

##### 非主流用法：
###### 使用image创建container并执行相应命令，然后停止
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;$ docker run centos echo ‘123’
Unable to find image ‘centos:latest’ locally
latest: Pulling from library/centos
af4b0a2388c6: Pull complete
Digest: sha256:2671f7a3eea36ce43609e9fe7435ade83094291055f1c96d9d1d1d7c0b986a5d
Status: Downloaded newer image for centos:latest
ps:以上是下载最新的centos过程
123&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;　　
这是最简单的方式，跟在本地直接执行echo &apos;hello world&apos; 几乎感觉不出任何区别，而实际上它会从本地 **centos:latest** 镜像启动到一个容器并执行打印命令后退出（docker ps -l可查看）。
　　
需要注意的是，默认有一个　**--rm=true**　参数，即完成操作后停止容器并从文件系统移除。
因为Docker的容器实在太轻量级了，很多时候用户都是随时删除和新创建容器。
容器启动后会自动随机生成一个CONTAINER ID，这个ID在后面commit命令后可以变为IMAGE ID

##### 主流用法：
###### 使用image创建container并进入交互模式, login shell是/bin/bash
`docker run -i --name cee -t centos:7.2.1511 /bin/bash`
使用示例：
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;docker run -i --name cee -t centos:7.2.1511 /bin/bash
[root@90df89d56b3e /]#
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用到的option：&lt;/p&gt;
&lt;p&gt;|参数|含义|
|—|—|—|
|-i |保持输入打开即使不连接（类似于后台运行）|
|–name |标记可以为容器自定义命名|
|-t |docker可以虚拟出一个&lt;a href=&quot;https://www.zhihu.com/question/21711307&quot;&gt;TTY窗口&lt;/a&gt;|&lt;/p&gt;
</content:encoded></item><item><title>Docker配置开发环境常用命令_参数详解(3</title><link>https://www.motouguai.com/note/docker-configuration-development-environment-commonly-used-commands-parameters-detailed-3/</link><guid isPermaLink="true">https://www.motouguai.com/note/docker-configuration-development-environment-commonly-used-commands-parameters-detailed-3/</guid><description>文章不兼容, 已放到时光机</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;文章不兼容, 已放到&lt;a href=&quot;https://web.archive.org/web/20190805030547/https://www.fenxiangy.com/note/dockercmdthree.html&quot;&gt;时光机&lt;/a&gt;&lt;/h1&gt;
</content:encoded></item><item><title>Docker镜像下载\删除\查看命令_参数详解</title><link>https://www.motouguai.com/note/docker-image-download-delete-view-command-parameters-detailed/</link><guid isPermaLink="true">https://www.motouguai.com/note/docker-image-download-delete-view-command-parameters-detailed/</guid><description>标签（空格分隔）： docker 镜像 下载\删除\查看: 镜像 下载: 1) . 下载最新系统 1docker pull centos 这里的centos是系统,如果后面不指定系统详细版本号会下载镜像源最新系统 * 2).*下载指定版本系统** 1docker pull centos:6.6 下载不同版本在centos后面加上冒号然后是版本</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： docker&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;镜像 下载\删除\查看:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;镜像 下载:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;. &lt;strong&gt;下载最新系统&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;docker pull centos
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;_这里的centos是系统,如果后面不指定系统详细版本号会下载镜像源最新系统 *
　　
2).*_下载指定版本系统**&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker pull centos:6.6
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;下载不同版本在centos后面加上冒号然后是版本号&lt;/strong&gt;
　　
&lt;strong&gt;后面使用的版本号依据搜索出来的镜像提供的一些版本编号来填写&lt;/strong&gt;
　　
&lt;img src=&quot;http://fenxiangy-ftp.test.upcdn.net/wp-content/uploads/2018/02/360%E6%88%AA%E5%9B%BE1681031110097113-300x210.png&quot; alt=&quot;Docker Hub 官方镜像版本标签&quot; /&gt;&lt;/p&gt;
&lt;p&gt;3).&lt;strong&gt;Docker常用搜索镜像下载地址:&lt;/strong&gt;
&lt;a href=&quot;https://hub.docker.com/_/centos/&quot;&gt;Docker官网的镜像搜索&lt;/a&gt;
&lt;a href=&quot;https://dev.aliyun.com/list.html?namePrefix=centos&quot;&gt;阿里云提供的国内镜像下载&lt;/a&gt; 　　&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;镜像 删除\查看:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1.&lt;strong&gt;停止所有&lt;/strong&gt;的经过镜像实例化运行的容器，这样才能够删除其中的images：
　　
查看容器:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;docker ps
主要有些参数要说一下
1. 不加参数，表示查看当前正在运行的容器
2. -a，查看所有容器包括停止状态的容器
3. -l，查看最新创建的容器
4. -n=x，查看最后创建的x个容器
列一下docker ps的结果
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
这些分别代表什么
CONTAINER ID：容器ID，唯一标识容器
IMAGE：创建容器时所用的镜像
COMMAND：在容器最后运行的命令
CREATED：容器创建的时间
STATUS：容器的状态（你会看到UPXXX，表示运行状态）
PORTS：对外开放的端口号
NAMES：容器名（也具有唯一性，docker是不允许创建容器名相同的容器的）
&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;options
名字 简写 默认 描述
–time -t 10 秒杀之前等待停止&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2.查看当前有些什么images

```docker images
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.删除images，通过image的id来指定删除谁&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
```text
options
  名字     简写	     描述
--force    -f		强制删除图像
--no-prune		不要删除未标记的父母
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;例子:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code&gt;$ docker images

REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
test1                     latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)
test                      latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)
test2                     latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)

$ docker rmi fd484f19954f

Error: Conflict, cannot delete image fd484f19954f because it is tagged in multiple repositories, use -f to force
2013/12/11 05:47:16 Error: failed to remove one or more images

$ docker rmi test1

Untagged: test1:latest

$ docker rmi test2

Untagged: test2:latest


$ docker images

REPOSITORY                TAG                 IMAGE ID            CREATED             SIZE
test                      latest              fd484f19954f        23 seconds ago      7 B (virtual 4.964 MB)

$ docker rmi test

Untagged: test:latest
Deleted: fd484f19954f4920da7ff372b5067f5b7ddb2fd3830cecd17b96ea9e286ba5b8
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;#### 问题回顾 　　 删除时出现 　　&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker rmi  196e0ce0c9fb
Error response from daemon: conflict: unable to delete 196e0ce0c9fb (must be forced) - image is referenced in multiple repositories
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;　　
可以尝试
　　
&lt;code&gt;docker rmi daocloud.io/centos #REPOSITORY 栏中的文字&lt;/code&gt;
　　
再次删除时出现
　　
&lt;code&gt;Untagged: daocloud.io/centos:latest&lt;/code&gt;
　　
尝试删除
　　
&lt;code&gt;docker rmi #IMAGE ID 栏中的文字&lt;/code&gt;
　　
问题示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
daocloud.io/centos   7                   196e0ce0c9fb        5 months ago        197MB
daocloud.io/centos   latest              196e0ce0c9fb        5 months ago        197MB

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker rmi  196e0ce0c9fb
Error response from daemon: conflict: unable to delete 196e0ce0c9fb (must be forced) - image is referenced in multiple repositories

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker rmi daocloud.io/centos
Untagged: daocloud.io/centos:latest

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker images
REPOSITORY           TAG                 IMAGE ID            CREATED             SIZE
daocloud.io/centos   7                   196e0ce0c9fb        5 months ago        197MB

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker rmi daocloud.io/centos
Error: No such image: daocloud.io/centos

Administrator@DESKTOP-679OPI8 MINGW64 ~
$ docker rmi 196e0ce0c9fb
Untagged: daocloud.io/centos:7
Untagged: daocloud.io/centos@sha256:822de5245dc5b659df56dd32795b08ae42db4cc901f3462fc509e91e97132dc0
Deleted: sha256:196e0ce0c9fbb31da595b893dd39bc9fd4aa78a474bbdc21459a3ebe855b7768
Deleted: sha256:cf516324493c00941ac20020801553e87ed24c564fb3f269409ad138945948d4
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>vagrant使用记录</title><link>https://www.motouguai.com/note/vagrant-usage-record/</link><guid isPermaLink="true">https://www.motouguai.com/note/vagrant-usage-record/</guid><description>标签（空格分隔）： vagrant 看本文首先你要对vagrant有一定了解 传送门 从网上搜索国内镜像源,他们说官方有cdn那就从官方搜索下载了 Vagrant 就是使用 Ruby 写成的, 所以在这里的配置文件也需要满足 Ruby 语法。 config.vm.box = “ubuntu/trusty64”可以看到，这两行就是我们在vagrant init</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/usr/uploads/2018/07/286915945.jpg&quot; alt=&quot;vagrant使用记录&quot; /&gt;&lt;/h1&gt;
&lt;p&gt;标签（空格分隔）： vagrant&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;看本文首先你要对vagrant有一定了解 &lt;a href=&quot;https://www.jianshu.com/p/2d4afce8fe12&quot;&gt;传送门&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从网上搜索国内镜像源,他们说官方有cdn那就从&lt;a href=&quot;https://app.vagrantup.com/boxes/search&quot;&gt;官方搜索&lt;/a&gt;下载了&lt;/p&gt;
&lt;p&gt;Vagrant 就是使用 Ruby 写成的, 所以在这里的配置文件也需要满足 Ruby 语法。&lt;/p&gt;
&lt;p&gt;config.vm.box = “ubuntu/trusty64”
可以看到，这两行就是我们在vagrant init中后面所指定的参数。由此可以看出，vagrant init只是帮我们生成了配置文件而已，换句话说，如果我们写好了Vagrantfile，就不需要vagrant init，只需将准备好的配置文件放入到所需目录中，然后直接执行vagrant up即可。&lt;/p&gt;
&lt;p&gt;还有很多注释掉的配置，那些都是一些常用的配置，包括网卡设置、IP地址、绑定目录，甚至可以指定内存大小、CPU个数、是否启动界面等等。如果需要，可以根据注释文本进行配置。&lt;/p&gt;
&lt;p&gt;下面列出一些常用的配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.vm.hostname：配置虚拟机主机名

config.vm.network：这是配置虚拟机网络，由于比较复杂，我们其后单独讨论

config.vm.synced_folder：除了默认的目录绑定外，还可以手动指定绑定

config.ssh.username：默认的用户是vagrant，从官方下载的box往往使用的是这个用户名。如果是自定制的box，所使用的用户名可能会有所不同，通过这个配置设定所用的用户名。

config.vm.provision：我们可以通过这个配置在虚拟机第一次启动的时候进行一些安装配置，后面我们将专门介绍。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;需要注意的是，Vagrantfile文件只会在第一次执行vagrant up时调用执行，其后如果不明确使用vagrant reload，则不会被强制重新加载。&lt;/p&gt;
&lt;p&gt;config.vm.network”forwarded_port”,guest:80,host:8080
这将让物理机的8080端口映射到虚拟机的80端口。因此，可以在物理机上直接访问虚拟机所建立的网站。这在虚拟机使用不是桥接的时候尤为重要，因为很多时候默认会禁止物理机通过网络直接访问虚拟机，通过端口映射可以依旧能够访问所需端口。&lt;/p&gt;
&lt;p&gt;我们还可以通过config.vm.network来指定所在网络以及IP地址。一般来说，分为private_network还是public_network。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private_network： 私有网络
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;位于私有网络的主机之间可以互相访问，但是外界无法访问私有网络的主机，对于某些虚拟机而言，连物理机都无法通过网络直接访问虚拟机，此时如果需要使用物理机访问虚拟机，就需要前面所提及的端口映射。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.vm.network&quot;private_network&quot;,ip:&quot;192.168.33.10&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;public_network：公有网络
在绝大多数虚拟机上，这等同于桥接网络。如果虚拟机选择了桥接方式连接，也就是相当于虚拟机和物理机在网络上处于平等的位置，同样的接在了网卡所在的网络。因此从外界看来，会感觉这是两台独立的计算机。&lt;/p&gt;
&lt;p&gt;配置方式和私有网络接近，只需将其中的private_network换成public_network。如要使用 DHCP：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.vm.network&quot;public_network&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果物理机存在多块网卡，需要指定某一块作为桥接用，那么可以参考如下配置：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;config.vm.network&quot;public_network&quot;,:bridge=&amp;gt;&apos;en1: Wi-Fi (AirPort)&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果是在启动了虚拟机之后，需要重新加载配置，只需要执行：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;vagrant reload
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;vagrant基本命令，根据操作的目的，可以对基本命令进行分类：
1 操作镜像
box package
2 操作虚拟机
connect destroy halt init powershell provision rdp reload resume share snapshot ssh suspend up
3 监控虚拟机
global-status ssh-config port status
4 其他
help login plugin push version&lt;/p&gt;
&lt;p&gt;1 操作镜像
该命令有两个，用来管理本地镜像
1.1 vagrant box
1.1.1 添加镜像到本地仓库
$ vagrant box add [box-name] [box镜像文件或镜像名]&lt;/p&gt;
&lt;p&gt;1.1.2 移除本地镜像
$ vagrant box remove [box-name]&lt;/p&gt;
&lt;p&gt;box多版本共存的情况
如果box升级过，那么在box list中会出现两个同名，但版本不同的镜像。如：
$ vagrant box list |grep coreos
coreos-alpha (virtualbox, 745.1.0)
coreos-alpha (virtualbox, 928.0.0)&lt;/p&gt;
&lt;p&gt;使用该镜像创建虚拟机的时候，默认会使用高版本的box。
如果想使用低版本，需要修改Vagrantfile,指定box-version
在config.vm.box=xxx下一行，如上面的例子中，在“config.vm.box = “coreos-alpha””后面增加一行配置信息：
config.vm.box_version = “745.1.0”&lt;/p&gt;
&lt;p&gt;同样，如果想删除一个box，如下操作会失败：
$ vagrant box remove coreos-alpha
You requested to remove the box ‘coreos-alpha’ with provider
‘virtualbox’. This box has multiple versions. You must
explicitly specify which version you want to remove with
the &lt;code&gt;--box-version&lt;/code&gt; flag or specify the &lt;code&gt;--all&lt;/code&gt; flag to remove all
versions. The available versions for this box are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;745.1.0&lt;/li&gt;
&lt;li&gt;928.0.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这时有两个选择：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;vagrant box remove coreos-alpha –all
删除所有同名镜像&lt;/li&gt;
&lt;li&gt;vagrant box remove coreos-alpha –box-version=745.1.0
删除指定版本的镜像&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;1.1.3 升级镜像
检查镜像是否有升级？
$ cd ~/vm/ubuntu
$ vagrant box outdated
Checking if box ‘ubuntu/trusty64’ is up to date…
A newer version of the box ‘ubuntu/precise64’ is available! You currently
have version ‘20160122.0.0’. The latest is version ‘20160209.0.0’. Run
&lt;code&gt;vagrant box update&lt;/code&gt; to update.&lt;/p&gt;
&lt;p&gt;中央仓库有新版更新了，手动更新box。更新的结果并不是替换旧版本，而是在本地仓库中增加了新版的box镜像。
$ cd ~/vm/ubuntu
$ vagrant box update
==&amp;gt; default: Checking for updates to ‘ubuntu/precise64’
default: Latest installed version: 20160120.0.0
default: Version constraints:
default: Provider: virtualbox
==&amp;gt; default: Updating ‘ubuntu/precise64’ with provider ‘virtualbox’ from version
==&amp;gt; default: ‘20160120.0.0’ to ‘20160201.0.0’…
==&amp;gt; default: Loading metadata for box ‘&lt;a href=&quot;https://atlas.hashicorp.com/ubuntu/precise64?access_token=cXR0wCgWXoRpMw.atlasv1.ydBAS4ev1YCWzSK4S1l6iVjssRbO5Q50a8YVnEPqoyYjcQVeaMdEsiQ8rz8tOcSHLuY&apos;&quot;&gt;https://atlas.hashicorp.com/ubuntu/precise64?access_token=cXR0wCgWXoRpMw.atlasv1.ydBAS4ev1YCWzSK4S1l6iVjssRbO5Q50a8YVnEPqoyYjcQVeaMdEsiQ8rz8tOcSHLuY&apos;&lt;/a&gt;
==&amp;gt; default: Adding box ‘ubuntu/precise64’ (v20160201.0.0) for provider: virtualbox
default: Downloading: &lt;a href=&quot;https://atlas.hashicorp.com/ubuntu/boxes/precise64/versions/20160201.0.0/providers/virtualbox.box&quot;&gt;https://atlas.hashicorp.com/ubuntu/boxes/precise64/versions/20160201.0.0/providers/virtualbox.box&lt;/a&gt;
==&amp;gt; default: Successfully added box ‘ubuntu/precise64’ (v20160201.0.0) for ‘virtualbox’!&lt;/p&gt;
&lt;p&gt;$ vagrant box list | grep precise64
ubuntu/precise64 (virtualbox, 20160120.0.0)
ubuntu/precise64 (virtualbox, 20160201.0.0)&lt;/p&gt;
&lt;p&gt;也可以检查本地仓库中的所有镜像是否有升级,使用 –global 开关，这时候不需要进入工作目录
$ vagrant box outdated –global&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;‘ubuntu/trusty64’ is outdated! Current: 20160122.0.0. Latest: 20160209.0.0&lt;/li&gt;
&lt;li&gt;‘ubuntu/precise64’ (v20160201.0.0) is up to date&lt;/li&gt;
&lt;li&gt;‘pollyduan/bento_oracle_xe’ wasn’t added from a catalog, no version information&lt;/li&gt;
&lt;li&gt;‘phusion/ubuntu-14.04-amd64’ (v2014.04.30) is up to date&lt;/li&gt;
&lt;li&gt;‘hashicorp/precise32’ (v1.0.0) is up to date&lt;/li&gt;
&lt;li&gt;‘hashicorp/boot2docker’ (v1.7.8) is up to date&lt;/li&gt;
&lt;li&gt;‘debian/jessie64’ wasn’t added from a catalog, no version information&lt;/li&gt;
&lt;li&gt;‘coreos-alpha’ is outdated! Current: 928.0.0. Latest: 955.0.0&lt;/li&gt;
&lt;li&gt;‘centos7’ wasn’t added from a catalog, no version information&lt;/li&gt;
&lt;li&gt;‘centos65’ wasn’t added from a catalog, no version information&lt;/li&gt;
&lt;li&gt;‘centos64’ wasn’t added from a catalog, no version information&lt;/li&gt;
&lt;li&gt;‘bento/ubuntu-14.04’ (v2.2.3) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/opensuse-13.2-x86_64’ (v2.2.1) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/freebsd-10.2’ (v2.2.3) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/fedora-22’ (v2.2.3) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/debian-8.2’ (v2.2.3) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/centos-7.2’ (v2.2.3) is up to date&lt;/li&gt;
&lt;li&gt;‘bento/centos-6.7’ (v2.2.3) is up to date&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不进入工作目录进行升级
$ vagrant box update –box coreos-alpha
Checking for updates to ‘coreos-alpha’
Latest installed version: 928.0.0
Version constraints: &amp;gt; 928.0.0
Provider: virtualbox
Updating ‘coreos-alpha’ with provider ‘virtualbox’ from version
‘928.0.0’ to ‘955.0.0’…
Loading metadata for box ‘&lt;a href=&quot;http://alpha.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json&apos;&quot;&gt;http://alpha.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json&apos;&lt;/a&gt;
Adding box ‘coreos-alpha’ (v955.0.0) for provider: virtualbox
Downloading: &lt;a href=&quot;http://alpha.release.core-os.net/amd64-usr/955.0.0/coreos_production_vagrant.box&quot;&gt;http://alpha.release.core-os.net/amd64-usr/955.0.0/coreos_production_vagrant.box&lt;/a&gt;
Box download is resuming from prior download progress
Progress: 1% (Rate: 92912/s, Estimated time remaining: 0:38:09)
…&lt;/p&gt;
&lt;p&gt;1.2 打包镜像
创建vm以后，我们自己根据需要安装软件，配置环境，都一切就绪了。如何分发给小伙伴使用呢？这里就要涌到package命令了，把镜像打包分发。
$ ll ~/VirtualBox\ VMs/ |grep ubuntu
drwx—— 6 pollyduan staff 204 2 2 11:18 ubuntu_default_1453944793418_7699
先看一下我们的vm目录名，这里有个容易混淆的目录：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vagrantfile所在的目录——vagrant的工作目录&lt;/li&gt;
&lt;li&gt;虚拟机文件所在的目录——virtualbox的工作目录
这两个目录名不一定相同，如果在Vagrantfile中指定了vb.name，virtualbox工作目录就取这个名字；否则，命名为：vagrant工作目录_随机字符串。
或者，也可以使用virtual box的管理工具来看vm的名称。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$ VBoxManage list vms|grep ubuntu
“ubuntu_default_1453944793418_7699” {0362edc2-548b-400b-a55d-776b0a24cd8d}&lt;/p&gt;
&lt;p&gt;package命令要使用的是virtual box工作目录。&lt;/p&gt;
&lt;p&gt;格式：vagrant package –base [virtualbox的工作目录] –output [保存的文件名，缺省为package.box]&lt;/p&gt;
&lt;p&gt;$ vagrant package –base ubuntu_default_1453944793418_7699 –output ubuntu_myproject_test.box
==&amp;gt; ubuntu_default_1453944793418_7699: Clearing any previously set forwarded ports…
==&amp;gt; ubuntu_default_1453944793418_7699: Exporting VM…
==&amp;gt; ubuntu_default_1453944793418_7699: Compressing package to: /Users/pollyduan/vm/tmp/ubuntu_myproject_test.box&lt;/p&gt;
&lt;p&gt;导出后，可以通过IM、ftp或其他方式分发给小伙伴，那么大家使用的环境就是一致的了。&lt;/p&gt;
&lt;p&gt;2 操作虚拟机&lt;/p&gt;
&lt;p&gt;2.1 启动vm&lt;/p&gt;
&lt;p&gt;2.1.1 对于单虚拟机
$ vagrant up&lt;/p&gt;
&lt;p&gt;2.1.2 如果同一个Vagrantfile定义了一个以上的虚拟机，则：
$ vagrant up [vm-name]
其他命令类似。如果省略vm-name，则依次启动所有vm。&lt;/p&gt;
&lt;p&gt;2.2 重启
$ vagrant reload [vm-name]&lt;/p&gt;
&lt;p&gt;2.3 关机
$ vagrant halt [vm-name]&lt;/p&gt;
&lt;p&gt;2.4 销毁虚拟机
$ vagrant destroy [vm-name]&lt;/p&gt;
&lt;p&gt;2.5 ssh登录虚拟机
$ vagrant ssh [vm-name]&lt;/p&gt;
&lt;p&gt;2.6 休眠与唤醒
这一对冤家也无需多说，对于开发环境来说，个人觉得用处不是很大。
$ vagrant suspend
==&amp;gt; default: Saving VM state and suspending execution…
$ vagrant status
Current machine states:&lt;/p&gt;
&lt;p&gt;default saved (virtualbox)&lt;/p&gt;
&lt;p&gt;To resume this VM, simply run &lt;code&gt;vagrant up&lt;/code&gt;.
$ vagrant resume
==&amp;gt; default: Resuming suspended VM…
==&amp;gt; default: Booting VM…
……&lt;/p&gt;
&lt;p&gt;2.7 快照
vagrant snapshot命令是vm的月光宝盒，如果vm中有任务没有跑完，需要关闭virtual box，就可以给vm做一个快照，保存vm当前所有的状态，在virtualbox重新启动后，再回复快照。
2.7.1 查看当前保存的快照
$ vagrant snapshot list
==&amp;gt; default: No snapshots have been taken yet!&lt;/p&gt;
&lt;p&gt;2.7.2 创建一个命名快照
$ vagrant snapshot save shot1
==&amp;gt; default: Snapshotting the machine as ‘shot1’…
$ vagrant snapshot list
shot1&lt;/p&gt;
&lt;p&gt;2.7.3 恢复快照
$ vagrant snapshot restore shot1
==&amp;gt; default: Forcing shutdown of VM…
==&amp;gt; default: Restoring the snapshot ‘shot1’…
……&lt;/p&gt;
&lt;p&gt;恢复后，快照会一直存在，直到你手动删除它。&lt;/p&gt;
&lt;p&gt;2.7.4 删除快照
$ vagrant snapshot delete shot1
==&amp;gt; default: Deleting the snapshot ‘shot1’…
Progress: 90%
Progress: 100%
==&amp;gt; default: Snapshot deleted!&lt;/p&gt;
&lt;p&gt;这个操作会删除持久化的数据文件，稍微有点慢，耐心等待。这个内在的原理没有深入研究，有点不太理解，删除一个文件理论上应该比保存一个文件更快才对。&lt;/p&gt;
&lt;p&gt;2.7.5 盗梦空间
push和pop，每调用一次push命令会自动创建一个命名快照，名为：push+一串随机数，如：push_1455524411_6632；每调用一次pop，会逐级恢复到最新的快照，并删除快照。看例子：
$ vagrant snapshot list
==&amp;gt; default: No snapshots have been taken yet!
$ vagrant snapshot push
==&amp;gt; default: Snapshotting the machine as ‘push_1455525041_2882’…
$ vagrant snapshot list
push_1455525041_2882
$ vagrant snapshot push
==&amp;gt; default: Snapshotting the machine as ‘push_1455525049_7456’…
$ vagrant snapshot push
==&amp;gt; default: Snapshotting the machine as ‘push_1455525058_6891’…
$ vagrant snapshot list
push_1455525041_2882
push_1455525049_7456
push_1455525058_6891
$ vagrant snapshot pop
==&amp;gt; default: Forcing shutdown of VM…
==&amp;gt; default: Restoring the snapshot ‘push_1455525058_6891’…
==&amp;gt; default: Deleting the snapshot ‘push_1455525058_6891’…
==&amp;gt; default: Snapshot deleted!
$ vagrant snapshot list
push_1455525041_2882
push_1455525049_7456&lt;/p&gt;
&lt;p&gt;Tips: 文本的日志看起来还不够形象，在push三个snapshot后在virtual box中是树形显示的；每次pop，树枝会逐级退回，看起来更像穿越的感觉。
Tips: 在pop清空之前，随时可以通过restore恢复其中一个快照，同样快照不会删除；不影响pop的测试。&lt;/p&gt;
&lt;p&gt;2.8 远程连接分享
远程连接通过share connect两个命令可以实现通过本机vagrant连接另外一台host上的虚机。
2.8.1 允许ssh连接
$ vagrant share –ssh
==&amp;gt; default: Detecting network information for machine…
default: Local machine address: 127.0.0.1
default:
default: Note: With the local address (127.0.0.1), Vagrant Share can only
default: share any ports you have forwarded. Assign an IP or address to your
default: machine to expose all TCP ports. Consult the documentation
default: for your provider (‘virtualbox’) for more information.
default:
default: An HTTP port couldn’t be detected! Since SSH is enabled, this is
default: not an error. If you want to share both SSH and HTTP, please set
default: an HTTP port with &lt;code&gt;--http&lt;/code&gt;.
default:
default: Local HTTP port: disabled
default: Local HTTPS port: disabled
default: SSH Port: 2200
default: Port: 2200
==&amp;gt; default: Generating new SSH key…
default: Please enter a password to encrypt the key: [输入授权密码]
default: Repeat the password to confirm:[再输一次]
default: Inserting generated SSH key into machine…
==&amp;gt; default: Checking authentication and authorization…
==&amp;gt; default: Creating Vagrant Share session…
default: Share will be at: vile-ibex-8238
==&amp;gt; default: Your Vagrant Share is running! Name: vile-ibex-8238
==&amp;gt; default:
==&amp;gt; default: You’re sharing your Vagrant machine in “restricted” mode. This
==&amp;gt; default: means that only the ports listed above will be accessible by
==&amp;gt; default: other users (either via the web URL or using &lt;code&gt;vagrant connect&lt;/code&gt;).
==&amp;gt; default:
==&amp;gt; default: You’re sharing with SSH access. This means that another user
==&amp;gt; default: simply has to run &lt;code&gt;vagrant connect --ssh vile-ibex-8238&lt;/code&gt;
==&amp;gt; default: to SSH to your Vagrant machine.
==&amp;gt; default:
==&amp;gt; default: Because you encrypted your SSH private key with a password,
==&amp;gt; default: the other user will be prompted for this password when they
==&amp;gt; default: run &lt;code&gt;vagrant connect --ssh&lt;/code&gt;. Please share this password with them
==&amp;gt; default: in some secure way.&lt;/p&gt;
&lt;p&gt;Tips: 你可以通过–name指定一个名称，否则会随机生成一个共享名，如本例中的vile-ibex-8238&lt;/p&gt;
&lt;p&gt;2.8.2 连接远端ssh虚机
$ vagrant connect –ssh vile-ibex-8238 –static-ip 10.2.136.211
Loading share ‘vile-ibex-8238’…
The SSH key to connect to this share is encrypted. You will require
the password entered when creating to share to decrypt it. Verify you
access to this password before continuing.&lt;/p&gt;
&lt;p&gt;Press enter to continue, or Ctrl-C to exit now.[回车]
Password for the private key:[输入授权密码]
Executing SSH…
vagrant@vagrant-ubuntu-trusty-64:~$&lt;/p&gt;
&lt;p&gt;2.8.3 共享http
vagrant share可以把host主机的http开放到远端，供任何人访问，这好像跟vm没什么关系，但的确它发生了。
$ ~/apache-tomcat-8.0.28/bin/startup.sh
$ vagrant share –http 80
==&amp;gt; default: Detecting network information for machine…
default: Local machine address: 127.0.0.1
default:
default: Note: With the local address (127.0.0.1), Vagrant Share can only
default: share any ports you have forwarded. Assign an IP or address to your
default: machine to expose all TCP ports. Consult the documentation
default: for your provider (‘virtualbox’) for more information.
default:
default: Local HTTP port: 80
default: Local HTTPS port: disabled
default: Port: 2200
==&amp;gt; default: Checking authentication and authorization…
==&amp;gt; default: Creating Vagrant Share session…
default: Share will be at: enchanting-buffalo-1493
==&amp;gt; default: Your Vagrant Share is running! Name: enchanting-buffalo-1493
==&amp;gt; default: URL: &lt;a href=&quot;http://enchanting-buffalo-1493.vagrantshare.com&quot;&gt;http://enchanting-buffalo-1493.vagrantshare.com&lt;/a&gt;
==&amp;gt; default:
==&amp;gt; default: You’re sharing your Vagrant machine in “restricted” mode. This
==&amp;gt; default: means that only the ports listed above will be accessible by
==&amp;gt; default: other users (either via the web URL or using &lt;code&gt;vagrant connect&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;我的host电脑在内网，在外网的任意一台电脑上，访问&lt;a href=&quot;http://enchanting-buffalo-1493.vagrantshare.xn--com-3h9d05vwxiwz4cf55b250n.&quot;&gt;http://enchanting-buffalo-1493.vagrantshare.com，奇迹发生了。&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;话说这个有什么用呢？别忘记，vagrant有一个端口映射的功能，在后面的Vagrantfile配置里会提到，这样做的结果，就是可以在互联网任意一个角落可以访问到你的虚机的http服务。&lt;/p&gt;
&lt;p&gt;2.9 windows相关的操作
powershelgl和rdp是windows vm相关的操作，未做测试，忽略。&lt;/p&gt;
&lt;p&gt;2.10 虚机环境部署
provision用于通过Vagrantfile配置文件，对vm进行部署，如安装软件，发布应用等，在这里不多说，专门一章来记录。&lt;/p&gt;
&lt;p&gt;2.11 指定vmid操作虚拟机
在3.3.2中，我们可以看到当前工作机中的所有虚机，其中第一列数据为vmid，我们可以无需进入vagrant工作目录，操作这些虚机。如：
$ vagrant up 63093ce&lt;/p&gt;
&lt;p&gt;该方式适用于前面提到的up、reload、halt、destroy等命令。&lt;/p&gt;
&lt;p&gt;3 监控虚拟机
3.1 查看sshd配置信息
$ vagrant ssh-config
Host default
HostName 127.0.0.1
User vagrant
Port 2222
UserKnownHostsFile /dev/null
StrictHostKeyChecking no
PasswordAuthentication no
IdentityFile “/Users/pollyduan/vm/ubuntu/.vagrant/machines/default/virtualbox/private_key”
IdentitiesOnly yes
LogLevel FATAL&lt;/p&gt;
&lt;p&gt;3.2 查看虚拟机开放的端口
$ vagrant port
The forwarded ports for the machine are listed below. Please note that
these values may differ from values configured in the Vagrantfile if the
provider supports automatic port collision detection and resolution.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;22 (guest) =&amp;gt; 2222 (host)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3.3 查看虚拟机状态
3.3.1 查看当前vm状态
$ cd ~/vm/ubuntu
$ vagrant status
Current machine states:&lt;/p&gt;
&lt;p&gt;default poweroff (virtualbox)&lt;/p&gt;
&lt;p&gt;The VM is powered off. To restart the VM, simply run &lt;code&gt;vagrant up&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;状态可能是：
not create | 执行vagrant init命令后，从未启动过
poweroff | 关机
running | 运行中
saved | 休眠&lt;/p&gt;
&lt;p&gt;3.3.2 查看全部虚机状态
此命令无需进入vagrant工作目录。
$ vagrant global-status&lt;/p&gt;
&lt;h2&gt;id name provider state directory&lt;/h2&gt;
&lt;p&gt;be5dee2 mfsmaster virtualbox poweroff /Users/pollyduan/vm/mfs
a523de6 mfschunk1 virtualbox poweroff /Users/pollyduan/vm/mfs
8377e0d mfschunk2 virtualbox poweroff /Users/pollyduan/vm/mfs
b772b1f metalogger virtualbox poweroff /Users/pollyduan/vm/mfs
8a5f10e mfsclient virtualbox poweroff /Users/pollyduan/vm/mfs
63093ce default virtualbox poweroff /Users/pollyduan/vm/ubuntu&lt;/p&gt;
&lt;p&gt;你可能会发现，为什么有的是default，有的是有名字的。这就是因为mfsxxxx是在vagrantfile中指定了vb.name，他对应的virtualbox工作目录也是这个值，而ubuntu这个虚机没有指定，所以是default，而且其virtualbox工作目录也是比较长的——ubuntu_default_1453944793418_7699。&lt;/p&gt;
&lt;p&gt;global-status统计信息不是实时的，所有不能保证数据是绝对准确的。如果在vagrant up启动后，我们在virtualbox管理终端关闭vm，global-status是捕获不到的，它还是会显示running状态。
截至1.8.1还是这样的，应该算是一个bug。处女座可能无法接受这个现实，那么你可以进入vagrant工作目录，手动再指定一次vagrant halt，状态就同步了。&lt;/p&gt;
&lt;p&gt;4 其他命令
4.1 help
略。&lt;/p&gt;
&lt;p&gt;4.2 login
登录到中央仓库&lt;/p&gt;
&lt;p&gt;4.3 plugin
插件管理，略。&lt;/p&gt;
&lt;p&gt;4.4 push
发布镜像到中央仓库&lt;/p&gt;
&lt;p&gt;4.5 version
略。&lt;/p&gt;
</content:encoded></item><item><title>composer组件开发</title><link>https://www.motouguai.com/technology-php/composer-component-development/</link><guid isPermaLink="true">https://www.motouguai.com/technology-php/composer-component-development/</guid><description>标签（空格分隔）： composer组件开发 http://www.chenjie.info/1880 入门https://git-scm.com/book/zh/v1/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE git tag 标签使用https://packagist.org/about#how-</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： composer组件开发&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href=&quot;http://www.chenjie.info/1880&quot;&gt;http://www.chenjie.info/1880&lt;/a&gt; 入门
&lt;a href=&quot;https://git-scm.com/book/zh/v1/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE&quot;&gt;https://git-scm.com/book/zh/v1/Git-%E5%9F%BA%E7%A1%80-%E6%89%93%E6%A0%87%E7%AD%BE&lt;/a&gt; git tag 标签使用
&lt;a href=&quot;https://packagist.org/about#how-to-update-packages&quot;&gt;https://packagist.org/about#how-to-update-packages&lt;/a&gt; 官方教程(包括自动更新)&lt;/p&gt;
</content:encoded></item><item><title>前端翻译国际化</title><link>https://www.motouguai.com/technology-web/frontend-translation-internationalization/</link><guid isPermaLink="true">https://www.motouguai.com/technology-web/frontend-translation-internationalization/</guid><description>标签（空格分隔）： 网站国际化支持 在网站中加入: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/usr/uploads/2018/07/3505083288.jpg&quot; alt=&quot;前端翻译国际化&quot; /&gt;&lt;/h1&gt;
&lt;p&gt;标签（空格分隔）： 网站国际化支持&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;在网站中加入:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    var langPackage = {
        &quot;主题&quot;: &quot;Title&quot;,
        &quot;下一页&quot;: &quot;NextPage&quot;,
        &quot;末页&quot;: &quot;LastPage&quot;,
        &quot;首页&quot;: &quot; FirstPage &quot;,
        &quot;上一页&quot;: &quot; PreviousPage &quot;,
        &quot;待办工作&quot;: &quot;MyTasks&quot;,
        &quot;中&quot;: &quot;Middle&quot;,
        &quot;每页&quot;: &quot; EachPage &quot;,
        &quot;条&quot;: &quot; Record &quot;,
        &quot;共&quot;: &quot; Total &quot;,
        &quot;页&quot;: &quot; Page &quot;,
        &quot;第&quot;: &quot; Current &quot;,
        &quot;工作主题&quot;: &quot; ProcTitle&quot;
    };
    /*
            主调函数
            在 Jquery的 .read方法里调用 ReplaceChildChs($(document));
            或者页面的最后调用
            ReplaceChildChs($(document));
        */
    function ReplaceChildChs(nodeObj) {
        // if($(&quot;#hdfUseLang&quot;).val()==&quot;CN&quot;)return;
        if (nodeObj.children().length &amp;gt; 0) {
            nodeObj.children().each(function() {
                ReplaceChildChs($(this));
                //            if ($(this)[0].nodeName.toUpperCase() == &quot;TD&quot;){
                FindChsAndReplaceIt($(this));
                //            }
            });
        } else {
            FindChsAndReplaceIt(nodeObj);
        }
    }

    // 直接替换html 的一种设想，但总是报错
    function JustReplaceChsDom(nodeObj) {
        var pat = new RegExp(&quot;[\u4e00-\u9fa5]+&quot;, &quot;g&quot;); // 匹配中文的正则表达式
        var str = $(nodeObj).html();
        while ((arr = pat.exec(str)) != null) {
            if (langPackage[arr[0]]) {
                str = str.replace(arr[0], langPackage[arr[0]]);
            }
        }
        $(nodeObj).html(str);
    }

    function FindChsAndReplaceIt(nodeObj) {
        var pat = new RegExp(&quot;[\u4e00-\u9fa5]+&quot;, &quot;g&quot;);
        if ((nodeObj.text() || nodeObj.val() || nodeObj.attr(&quot;title&quot;)) &amp;amp;&amp;amp;
            (pat.exec(nodeObj.text()) || pat.exec(nodeObj.val()) || pat.exec(nodeObj.attr(&quot;title&quot;)))) {
            var str = &quot;&quot;
            if (nodeObj.text()) {
                str = nodeObj.text();
                ReplaceValue(str, nodeObj, &quot;text&quot;);
            }
            if (nodeObj.val()) {
                str = nodeObj.val();
                ReplaceValue(str, nodeObj, &quot;val&quot;);
            }
            if (nodeObj.attr(&quot;title&quot;)) {
                str = nodeObj.attr(&quot;title&quot;);
                ReplaceValue(str, nodeObj, &quot;title&quot;);
            }
        }
    }

    function ReplaceValue(str, nodeObj, attrType) {
        var arr;
        var pat = new RegExp(&quot;[\u4e00-\u9fa5]+&quot;, &quot;g&quot;);
        while ((arr = pat.exec(str)) != null) {
            if (langPackage[arr[0]]) {
                str = str.replace(arr[0], langPackage[arr[0]]);

                if (attrType == &quot;text&quot;) {
                    nodeObj.text(str);
                } else if (attrType == &quot;val&quot;) {
                    nodeObj.val(str);
                } else if (attrType == &quot;title&quot;) {
                    nodeObj.attr(&quot;title&quot;, str);
                }
            }
        }
    }
    ReplaceChildChs($(document));
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;上面数组进行单词替换;
文章啥的最好还是有多语言的支持&lt;/p&gt;
&lt;h3&gt;translate翻译方式 需要翻墙&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;google_translate_element&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
    function googleTranslateElementInit() {
        new google.translate.TranslateElement({
            pageLanguage: &apos;zh-CN&apos;,
            layout: google.translate.TranslateElement.InlineLayout.SIMPLE
        }, &apos;google_translate_element&apos;);
    }
&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;!-- Begin TranslateThis Button --&amp;gt;
&amp;lt;div id=&quot;translate-this&quot;&amp;gt;&amp;lt;a href=&quot;http://translateth.is/&quot; class=&quot;translate-this-button&quot;&amp;gt;Translate&amp;lt;/a&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://www.google.com/jsapi&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot; src=&quot;http://x.translateth.is/translate-this.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    TranslateThis();
&amp;lt;/script&amp;gt;
&amp;lt;!-- End TranslateThis Button --&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>node.js实现mqtt 发布/发送 消息到主题</title><link>https://www.motouguai.com/technology/web-nodemqtt/</link><guid isPermaLink="true">https://www.motouguai.com/technology/web-nodemqtt/</guid><description>标签（空格分隔）： mqtt mqtt是啥?我的博客有写这个东西:传送门 安装首先你要安装node.js和npm 教程传送门 随后找个文件夹执行 命令行 安装mqtt模块; 1npm install mqtt 如果需要服务端 执行 1npm install mosca 使用 mqtt的文档 以下代码中有些参数可以从mqtt官方文档中得到</description><pubDate>Tue, 10 Jul 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;标签（空格分隔）： mqtt&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;img src=&quot;https://www.motouguai.com/images/legacy/fenxiangy/usr/uploads/2018/07/3649892521.jpg&quot; alt=&quot;u=2264770358,3320226800&amp;amp;fm=27&amp;amp;gp=0.jpg&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mqtt是啥?我的博客有写这个东西:&lt;a href=&quot;/note/mqttprotocol/&quot;&gt;传送门&lt;/a&gt;
&lt;img src=&quot;http://fenxiangy-ftp.test.upcdn.net/wp-content/uploads/2018/03/9150e4e5gw1fbcgvwv9prg209w05kqv5.gif&quot; alt=&quot;此处输入图片的描述&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;安装&lt;/h3&gt;
&lt;p&gt;首先你要安装node.js和npm &lt;a href=&quot;https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/00143450141843488beddae2a1044cab5acb5125baf0882000&quot;&gt;教程传送门&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;随后找个文件夹执行 命令行 安装mqtt模块;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install mqtt
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;如果需要服务端 执行&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;npm install mosca
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;使用&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mcxiaoke.gitbooks.io/mqtt-cn/content/mqtt/02-ControlPacketFormat.html#221-mqtt%E6%8E%A7%E5%88%B6%E6%8A%A5%E6%96%87%E7%9A%84%E7%B1%BB%E5%9E%8B-mqtt-control-packet-type&quot;&gt;mqtt的文档&lt;/a&gt; 以下代码中有些参数可以从mqtt官方文档中得到解释&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.npmjs.com/package/mqtt&quot;&gt;node.js中mqtt模块文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/note/mqttprotocol/&quot;&gt;mqtt协议入门文章&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;服务端&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;var mosca = require(&apos;mosca&apos;);
//构建自带服务器
var MqttServer = new mosca.Server({
    port: 1883
});
//对服务器端口进行配置， 在此端口进行监听
MqttServer.on(&apos;clientConnected&apos;, function(client) {
    //监听连接
    console.log(&apos;client connected&apos;, client.id);
});
/**
 * 监听MQTT主题消息
 **/
MqttServer.on(&apos;published&apos;, function(packet, client) {
    //当客户端有连接发布主题消息
    var topic = packet.topic;
    console.log(packet);
    switch (topic) {
        case &apos;test&apos;:
            console.log(&apos;message-publish&apos;, packet.payload.toString());
            //MQTT转发主题消息
            MqttServer.publish({ topic: &apos;other&apos;, payload: &apos;sssss&apos; });
            break;
        case &apos;other&apos;:
            console.log(&apos;message-123&apos;, packet.payload.toString());
            break;
    }
});

MqttServer.on(&apos;ready&apos;, function() {
    //当服务开启时
    console.log(&apos;mqtt is running...&apos;);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;PS: 不推荐node.js 作服务端&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;发布消息到主题&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;var mqtt = require(&apos;mqtt&apos;);
var client = mqtt.connect(&apos;mqtt://127.0.0.1&apos;); //连接到服务端
//client.subscribe(&apos;presence&apos;);
var num = 0;
var qtt = {}; //定义消息（可以为字符串、对象等）
qtt = &apos;setr=xxxxxxx1xx&apos;;
setInterval(function() { //一秒钟发送一次 消息到主题 SN69143809293670state 消息为 setr=xxxxxxx1xx
    client.publish(&apos;SN69143809293670state&apos;, qtt, { qos: 0, retain: true });
}, 1000);
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;订阅主题&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt;var mqtt = require(&apos;mqtt&apos;);
var client2 = mqtt.connect(&quot;mqtt://127.0.0.1:1883&quot;);   //指定服务端地址和端口

client2.subscribe(&apos;test&apos;,{qos:1});//订阅主题为test的消息

client2.on(&apos;message&apos;,function(top,message) {
    console.log(message.toString());
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;制作接口(简化)&lt;/h4&gt;
&lt;p&gt;我所接触的这个物理设备是发送给他一个 控制 或者 查询 请求到&lt;code&gt;他订阅的&lt;/code&gt;主题中(ctr),
并且它接收到控制信息,去执行.执行成功时 则会将 &lt;code&gt;状态&lt;/code&gt; 发送到另一个 &lt;code&gt;我订阅的&lt;/code&gt;主题中 .
使用php实现比较麻烦,并且返回信息时有时无,使用node.js更方便,返回信息也更快;&lt;/p&gt;
&lt;p&gt;物理环境 :centos7.2 64位,装有mqtt服务代理端&lt;code&gt;mosquitto&lt;/code&gt;或其他mqtt协议代理. 安装可以自行搜索一下 和 node.js;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要安装http 和 express 以及 mqtt 模块 &lt;code&gt;npm install 模块名&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://nodejs.cn/api/http.html&quot;&gt;node.js http模块文档&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;var mqtt = require(&apos;mqtt&apos;);
var express = require(&quot;express&quot;);
var app = express();
var hostName = &apos;127.0.0.1&apos;; //http服务的提供服务ip
var port = 8080;
var num = 1;
person = new Object();
person.firstname = &quot;Bill&quot;;
app.all(&apos;*&apos;, function(req, res, next) {
    res.header(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;);
    res.header(&quot;Access-Control-Allow-Headers&quot;, &quot;Origin, X-Requested-With, Content-Type, Accept&quot;);
    res.header(&quot;Access-Control-Allow-Methods&quot;, &quot;PUT,POST,GET,DELETE,OPTIONS&quot;);
    res.header(&quot;X-Powered-By&quot;, &apos; 3.2.1&apos;)
    res.header(&quot;Content-Type&quot;, &quot;application/json;charset=utf-8&quot;);
    next();
});//json header头

app.get(&quot;/zhinengjiaju/get&quot;, function(req, res) {
    //如果有get请求/zhinengjiaju/get则执行回调中的代码(方便!)

    // console.log(&quot;请求url：&quot;, req.path)
    // console.log(&quot;请求参数：&quot;, req.query)
    req.setTimeout(200);
    //设置请求建立200ms 就中断接受请求,但还是在接收到返回信息后返回给它
    var client = mqtt.connect(&apos;mqtt://127.0.0.1:1883&apos;, {
        username: &apos;username&apos;,
        password: &apos;password&apos;,
        clientId: &apos;ap&apos; + num
    });
    //建立连接
    client.on(&apos;connect&apos;, function() {
        var sn = req.query.sn;
        var k = parseInt(req.query.k) - 1;
        // 127.0.0.1:8080/zhinengjiaju/get?sn=SN69143809293670&amp;amp;k=1&amp;amp;v=3&amp;amp;cmd=setr

        client.subscribe(sn + &apos;state&apos;, { qos: 1 });
        //开始订阅

        if (req.query.cmd != &apos;setr&apos;) {
            m = req.query.cmd;
            if (req.query.cmd == &apos;qk&apos;) {
                m = &apos;setr=1111111111&apos;;
            }
            if (req.query.cmd == &apos;qg&apos;) {
                m = &apos;setr=0000000000&apos;;
            }

        } else {
            var m = [&apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;, &apos;x&apos;];
            m[k] = req.query.v;;

            m = req.query.cmd + &apos;=&apos; + m.join(&apos;&apos;);
        }
        //一系列简单接口处理

        client.publish(sn + &apos;ctr&apos;, m, { qos: 1, retain: true }); // &apos;Hello mqtt &apos; + (num++)
        //发送
        client.end();
        //发送完后立即结束此次和服务端建立的请求
    });
    client.on(&apos;message&apos;, function(topic, message) {
        //订阅信息一直在运行,如果有设备返回信息到主题,就执行此回调
        aaak(message.toString());
        //将值通过aaak函数传递给res.end返回给页面数据;
        client.end();


    });

    function aaak(aaaa) {
        var objaaaa = JSON.parse(aaaa);
        // console.log(objaaaa);
        num++;
        client.end();
        res.end(aaaa);
    }

})

app.listen(port, hostName, function() {
    console.log(`服务器运行在http://${hostName}:${port}`);
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;谢谢支持,感觉不错打个赏;
&lt;img src=&quot;http://ww4.sinaimg.cn/large/9150e4e5ly1fjsmzvyyvpg206o06odfw.gif&quot; alt=&quot;打赏&quot; /&gt;&lt;/p&gt;
</content:encoded></item></channel></rss>