<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
    <title>转啊转</title>
    <link>https://gitlab.520531.xyz</link>
    <description>转啊转的博客,个人博客</description>
    <language>zh-CN</language>
    <item>
      <title>linux下websocket连接优化</title>
      <link>https://gitlab.520531.xyz/article/websocket-connection-optimistic</link>
      <content:encoded>&lt;p&gt;优化tcp/ip&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;cat &amp;gt;&amp;gt; /etc/sysctl.conf &amp;lt;&amp;lt; EOF # WebSocket 必备优化 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30 net.ipv4.ip_local_port_range = 1024 65535 net.core.somaxconn=65535 net.ipv4.tcp_max_syn_backlog=16384 EOF &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;生效&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;sysctl -p &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;修改 /etc/security/limits.conf，&lt;/p&gt; &lt;pre&gt;&lt;code&gt;*    soft    nofile    1048576 *    hard    nofile    1048576 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;nginx配置&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;user root; worker_processes auto; # 每个 worker 的 fd 上限 worker_rlimit_nofile 65536;   error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf;  events {  # 每个 worker 最大连接，调高到 4096（总连接 ≈ 8*4096=32k &amp;gt; 10000）     worker_connections 4096;  # 同时接受多个连接  multi_accept on;    # Linux 用 epoll（高效多路复用）     use epoll;    # 使用epoll 关掉惊群保护锁  accept_mutex off;  }  http {     log_format  main  '$remote_addr - $remote_user [$time_local] &amp;quot;$request&amp;quot; '        'Accept-encoding &amp;quot;$http_accept_encoding&amp;quot;'        'X-Request-With &amp;quot;$http_x_request_with&amp;quot;'                       '$status $body_bytes_sent &amp;quot;$http_referer&amp;quot; '                       '&amp;quot;$http_user_agent&amp;quot; &amp;quot;$http_x_forwarded_for&amp;quot; &amp;quot;$http_authorization&amp;quot;';      access_log  /var/log/nginx/access.log  main;      sendfile            on;     tcp_nopush          on;     tcp_nodelay         on;     keepalive_timeout   65;     types_hash_max_size 4096;  # ③ 加大缓冲，减少 slow system call  proxy_buffers 32 64k;  # ④ 首包更大，握手更快      proxy_buffer_size 128k;                 proxy_busy_buffers_size 128k;      include             /etc/nginx/mime.types;     default_type        application/octet-stream;     include /etc/nginx/conf.d/*.conf;    server {     listen       443 ssl http2;         server_name  sh.ixiatiao.com;         ssl_certificate &amp;quot;/etc/nginx/cert/sh.server.crt&amp;quot;;         ssl_certificate_key &amp;quot;/etc/nginx/ert/sh.server.key&amp;quot;;         ssl_session_cache shared:SSL:1m;         ssl_session_timeout  10m;         ssl_ciphers HIGH:!aNULL:!MD5;         ssl_prefer_server_ciphers on;   ssl_stapling on;   ssl_stapling_verify on;   resolver 8.8.8.8 8.8.4.4 223.5.5.5 119.29.29.29 valid=86400s;   resolver_timeout 5s;         # Load configuration files for the default server block.         include /etc/nginx/default.d/*.conf;   gzip on;   gzip_types text/css text/javascript text/xml text/plain text/x-component application/javascript application/json application/xml application/rss+xml font/truetype font/opentype application/vnd.ms-fontobject image/svg+xml;      # WebSocket 代理         location ^~ /user/session {             proxy_pass http://127.0.0.1:9981/user/session;             proxy_http_version 1.1;             proxy_set_header Upgrade $http_upgrade;             proxy_set_header Connection &amp;quot;Upgrade&amp;quot;;             proxy_set_header Host $http_host;             proxy_set_header X-Real-IP $remote_addr;             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;             proxy_set_header X-Forwarded-Proto $scheme;    # ⑥ 清除 Connection 头，让后端完全接管    proxy_set_header Connection &amp;quot;&amp;quot;;    # 防止长时间连接超时             proxy_read_timeout 86400;          }     } }  &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Tue, 02 Dec 2025 08:04:00 GMT</pubDate>
    </item>
    <item>
      <title>java stream contains 代码效率优化</title>
      <link>https://gitlab.520531.xyz/article/java-list-stream-execution-optimization</link>
      <content:encoded>&lt;pre&gt;&lt;code class="language-java"&gt;List&amp;lt;String&amp;gt; userIdList= refers.stream().filter(r -&amp;gt; Objects.equals(r.getAppCode(), f)).collect(Collectors.toList()).stream().map(AdReferVo::getUserId).collect(Collectors.toList()); List&amp;lt;LogAdVo&amp;gt; logs = logAds.stream().filter(t -&amp;gt; !userIds.contains(t.getUserId())).collect(Collectors.toList()); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;当上面第一步收集到list，然后在log判断 userIdList.contains(&amp;quot;xxx&amp;quot;)时，会产生很大的效率问题，由于log的数据量很大，当执行filter的时候，每个log都需要进行一次contain，而每个contain又会对userIdList遍历，也就是时间复杂度为 O(n), 而整个系统的时间复杂度就是O(n²)，会极大拖累系统的执行效率，上述代码在生产中百万级数据量耗时大概在10分钟。&lt;/p&gt; &lt;p&gt;现在优化页很简单，只需要把第一句修改为set数据结构，这样contain的时间复杂度就变成了O(1),系统整体时间复杂度就变成了O(n) 优化后如下:&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;Set&amp;lt;String&amp;gt; userIdList= refers.stream().filter(r -&amp;gt; Objects.equals(r.getAppCode(), f)).collect(Collectors.toList()).stream().map(AdReferVo::getUserId).collect(Collectors.toSet()); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;百万级数据时间约为5秒，当然还有其他一些逻辑在，这里省略&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 19 Nov 2025 05:38:00 GMT</pubDate>
    </item>
    <item>
      <title>如何修改android webview的x-request-with字段默认的包名</title>
      <link>https://gitlab.520531.xyz/article/rewrite-webview-x-request-with-package-name</link>
      <content:encoded>&lt;pre&gt;&lt;code class="language-js"&gt;package com.ug;  import android.app.Application;  public class CustomApplication extends Application {      @Override     public String getPackageName() {         StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();         for (StackTraceElement item : stackTrace) {             if (&amp;quot;org.chromium.base.BuildInfo&amp;quot;.equals(item.getClassName())) {                 if (&amp;quot;getAll&amp;quot;.equals(item.getMethodName())) {                     return &amp;quot;com.baidu.sdk&amp;quot;;                 }             }         }         return super.getPackageName();     } }  &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 04 Sep 2025 13:29:00 GMT</pubDate>
    </item>
    <item>
      <title>wsl2 ubuntu下运行docker-android重启后无法启动模拟器</title>
      <link>https://gitlab.520531.xyz/article/96</link>
      <content:encoded>&lt;p&gt;docker network create ug-network&lt;/p&gt; &lt;p&gt;docker run -d --network=ug-network -p 6080:6080 -p 5554:5554 -p 5555:5555 -v android11_1:/home/androidusr -e EMULATOR_DEVICE=&amp;quot;Samsung Galaxy S10&amp;quot; -e WEB_VNC=true --device /dev/kvm --name android11_1 budtmo/docker-android:emulator_11.0&lt;/p&gt; &lt;p&gt;重启后无法启动模拟器，就在wsl环境 root 用户手动执行 wsl中需要执行 docker exec -it -u0 android11_1 chmod 666 /dev/kvm docker exec -d android11_1 /usr/bin/emulator -avd  samsung_galaxy_s10_11.0&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 16 Jul 2025 16:40:00 GMT</pubDate>
    </item>
    <item>
      <title>jeecg-springboot2-vue2前端打包失败处理</title>
      <link>https://gitlab.520531.xyz/article/jeecg-springboot2-vue2-package-fail</link>
      <content:encoded>&lt;p&gt;如果使用已经封存的jeecg-boot-vue2版本，地址：https://github.com/jeecgboot/jeecgboot-vue2&lt;/p&gt; &lt;p&gt;前端代码会遇到可以npm run serve, 但是npm run build的时候却会报错，就是各种error，原因就是各种依赖冲突，这里只要在package.json,的dependencies增加如下代码，手动指定webpack的版本即可&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;&amp;quot;webpack&amp;quot;: &amp;quot;^4.5.0&amp;quot; &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Fri, 06 Dec 2024 10:05:00 GMT</pubDate>
    </item>
    <item>
      <title>selenium使用docker部署注意事项</title>
      <link>https://gitlab.520531.xyz/article/selenium-deploy-issue</link>
      <content:encoded>&lt;ol&gt; &lt;li&gt;首先，如果使用的springboot，那么在pom.xml中需配置，原因是，如果不指定，则会被springboot(2.7.12)默认指定为4.1.4，导致版本不统一&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code class="language-xml"&gt;&amp;lt;properties&amp;gt;     &amp;lt;selenium.version&amp;gt;4.19.1&amp;lt;/selenium.version&amp;gt; &amp;lt;/properties&amp;gt; &lt;/code&gt;&lt;/pre&gt; &lt;pre&gt;&lt;code class="language-xml"&gt;&amp;lt;dependency&amp;gt;   &amp;lt;groupId&amp;gt;org.seleniumhq.selenium&amp;lt;/groupId&amp;gt;   &amp;lt;artifactId&amp;gt;selenium-java&amp;lt;/artifactId&amp;gt;   &amp;lt;version&amp;gt;4.19.1&amp;lt;/version&amp;gt; &amp;lt;/dependency&amp;gt; &lt;/code&gt;&lt;/pre&gt; &lt;ol start="2"&gt; &lt;li&gt;docker部署命令&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code&gt;docker run -d -p 4444:4444 -p xxxx:7900 --shm-size=&amp;quot;2g&amp;quot; -e SE_NODE_GRID_URL=http://xxxx:xxxx:4444 -e SE_NODE_MAX_SESSIONS=5 -e SE_NODE_OVERRIDE_MAX_SESSIONS=true --name=selenium selenium/standalone-chrome:latest &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这里解释一下，因为部署在docker下，所以服务端返回的地址是docker内网地址，会导致无法连接devtools的websocket，所以这里需要指定环境变量SE_NODE_GRID_URL，手动指定服务器的域名和端口。 SE_NODE_OVERRIDE_MAX_SESSIONS 和 SE_NODE_MAX_SESSIONS 这两个是设定允许最大的会话数，一个是确认覆盖，另外一个是设置会话数量。以上内容全部参考：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;https://github.com/SeleniumHQ/selenium/issues/10117 https://github.com/SeleniumHQ/docker-selenium#grid-url-and-session-timeout &lt;/code&gt;&lt;/pre&gt; &lt;ol start="3"&gt; &lt;li&gt;7900为VNC端口，直接可以通过网页访问，4444为通讯端口&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code&gt;http://x.x.x.x:7900/?autoconnect=1&amp;amp;resize=scale&amp;amp;password=secret http://x.x.x.x:4444/ui/#/sessions 这个是ui http://x.x.x.x:4444/wd/hub/status 这个是状态端点 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;本地访问，注意webdriver和chrome版本一定要一致&lt;/p&gt; &lt;pre&gt;&lt;code&gt;//设置环境变量 System.setProperty(&amp;quot;webdriver.chrome.driver&amp;quot;,&amp;quot;C:\\dev\\driver\\chromedriver.exe&amp;quot;); // 创建 ChromeOptions 对象 ChromeOptions options = new ChromeOptions(); // 设置无界面模式 options.addArguments(&amp;quot;--headless&amp;quot;); //允许远程连接 options.addArguments(&amp;quot;--remote-allow-origins=*&amp;quot;); // 添加 --remote-debugging-port=9222 参数 options.addArguments(&amp;quot;--remote-debugging-port=9222&amp;quot;); //这里不要使用本地浏览器，版本会升级，切驱动号不一定对的上 options.setBinary(&amp;quot;C:\\dev\\driver\\chrome-win64\\chrome.exe&amp;quot;); driver = new ChromeDriver(options); devTools =  driver.getDevTools(); devTools.createSession(); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;附下载地址&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;https://googlechromelabs.github.io/chrome-for-testing/ &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 18 Apr 2024 15:54:00 GMT</pubDate>
    </item>
    <item>
      <title>git克隆仓库某个目录</title>
      <link>https://gitlab.520531.xyz/article/git-shell-commond</link>
      <content:encoded>&lt;pre&gt;&lt;code class="language-shell"&gt;// 1. 初始化 git init // 2. 设置仓库 git remote add origin xxx xxx为地址，例如:https://github.com/xx/xx.git // 3. 设置允许克隆子目录 git config core.sparsecheckout true // 4. 设置要克隆的仓库的相对根目录路径，xxx为路径（比如xxx/xx） echo 'xxx' &amp;gt;&amp;gt; .git/info/sparse-checkout // 5. 下载分支代码，xxx为分支（比如main） git pull origin xxx &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Sat, 30 Mar 2024 13:15:00 GMT</pubDate>
    </item>
    <item>
      <title>stream的toList坑点需要注意</title>
      <link>https://gitlab.520531.xyz/article/list-stream-bugs-0001</link>
      <content:encoded>&lt;p&gt;followerIdList.stream().map(String::valueOf).toList(); 返回的是unmodifiableList，因此是不可修改的，增加，删除等操作都是会报错的，使用时需要注意。&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 26 Mar 2024 07:00:00 GMT</pubDate>
    </item>
    <item>
      <title>使用@Builder注解需注意，mybatis查询报错</title>
      <link>https://gitlab.520531.xyz/article/java-sql-mybatis-builder-bug</link>
      <content:encoded>&lt;p&gt;@builder生成的构造方法会包含所有的属性，包括表示了 @TableField(exist = false) 的属性，所以&lt;/p&gt; &lt;p&gt;在org.apache.ibatis.executor.resultset.applyColumnOrderBasedConstructorAutomapping 创建映射生成结果集时，会导致数组越界 ~~String columnName = rsw.getColumnNames().get(i);~~&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;  private boolean applyColumnOrderBasedConstructorAutomapping(ResultSetWrapper rsw, List&amp;lt;Class&amp;lt;?&amp;gt;&amp;gt; constructorArgTypes,       List&amp;lt;Object&amp;gt; constructorArgs, Constructor&amp;lt;?&amp;gt; constructor, boolean foundValues) throws SQLException {     for (int i = 0; i &amp;lt; constructor.getParameterTypes().length; i++) {       Class&amp;lt;?&amp;gt; parameterType = constructor.getParameterTypes()[i];       String columnName = rsw.getColumnNames().get(i);       TypeHandler&amp;lt;?&amp;gt; typeHandler = rsw.getTypeHandler(parameterType, columnName);       Object value = typeHandler.getResult(rsw.getResultSet(), columnName);       constructorArgTypes.add(parameterType);       constructorArgs.add(value);       foundValues = value != null || foundValues;     }     return foundValues;   } &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Mon, 11 Mar 2024 14:50:00 GMT</pubDate>
    </item>
    <item>
      <title>黑苹果相关问题</title>
      <link>https://gitlab.520531.xyz/article/hackintosh-issue-resolve</link>
      <content:encoded>&lt;ol&gt; &lt;li&gt;应用提示损坏，让删除 打开终端，输入&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code class="language-js"&gt;sudo xattr -d com.apple.quarantine xxx.app &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;xxx.app可以从访达把应用直接拖进去&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 18 Jul 2023 15:06:00 GMT</pubDate>
    </item>
    <item>
      <title>fastjson，转json字符串异常</title>
      <link>https://gitlab.520531.xyz/article/fastjson-convert-excption-v1-2-78</link>
      <content:encoded>&lt;p&gt;fastJson1.2.78 偶尔会出现报错Comparison method violates its general contract!不是必然出现。&lt;/p&gt; &lt;p&gt;根据&lt;a href="https://mvnrepository.com/artifact/com.alibaba/fastjson" target="_blank"&gt;maven中央仓库&lt;/a&gt;信息，78版本存在漏洞，在1.2.83版已经修复，所以可以升级到83版本。&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 24 Mar 2023 04:16:00 GMT</pubDate>
    </item>
    <item>
      <title>springcloud个别服务实例下线，导致的异常处理</title>
      <link>https://gitlab.520531.xyz/article/springcloud-service-offline-error-handle</link>
      <content:encoded>&lt;h3&gt;当你使用eureka注册中心时，一定会遇到这种情况，就是请求的服务下线了，从而导致本次请求失败。&lt;/h3&gt; &lt;p&gt;无论你是怎么终止服务的 kill -15 还是 docker stop 或者docker-compose stop，上述的问题都不能从根本解决，根本原因就是请求者不知道服务已经下线了，那这里就衍生出&lt;/p&gt; &lt;p&gt;第一个思路，就是应用软下线，下线之前通知其他服务自己下线了，可以使用mq，或者使用发送rest请求，其他应用对其订阅或者处理即可&lt;/p&gt; &lt;p&gt;第二种方法，在使用shell部署应用时调用需要更新应用主动发起下线&lt;/p&gt; &lt;p&gt;代码如下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt; /**  * 服务主动上下线  * @author xiatiao  */ @Slf4j @ConditionalOnClass({EurekaAutoServiceRegistration.class}) @RequestMapping(&amp;quot;/application&amp;quot;) @RestController public class ApplicationController {      @Resource     EurekaAutoServiceRegistration eurekaAutoServiceRegistration;      @GetMapping(&amp;quot;/online&amp;quot;)     public Result&amp;lt;?&amp;gt; online() {         eurekaAutoServiceRegistration.start();         return Result.OK();     }      @GetMapping(&amp;quot;/offline&amp;quot;)     public Result&amp;lt;?&amp;gt; offline() {         eurekaAutoServiceRegistration.stop();         return Result.OK();     } }  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;主动下线后，shell可以sleep一段时间后，再执行真正的停止程序。&lt;/p&gt; &lt;p&gt;最后一种就是使用重试机制，当请求的服务出现500系错误以后，发起一次重试 ，可以在gateway的yml配置&lt;/p&gt; &lt;pre&gt;&lt;code class="language-yml"&gt;          filters:             - name: Retry               args:                 retries: 1                 statuses: BAD_GATEWAY,INTERNAL_SERVER_ERROR,SERVICE_UNAVAILABLE                 series: SERVER_ERROR &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 09 Mar 2023 07:40:00 GMT</pubDate>
    </item>
    <item>
      <title>记一次包冲突的解决</title>
      <link>https://gitlab.520531.xyz/article/java-package-conflict-resolve</link>
      <content:encoded>&lt;p&gt;app后端管理接入了友盟，需要查看一些用户活跃度信息，添加了umeng-api-client-0.0.1-SNAPSHOT.jar依赖后，正常的服务报错，java.lang.NoClassDefFoundError: Could not initialize class xxx ，经过代码断点追踪，确认是jar冲突导致，因为友盟的包里也有fastjson内容，但是版本较老。而类加载的时候如果fastjson的类已经加载过了，那就不会再重新加载正确的fastjson，从而导致找不到类。&lt;/p&gt; &lt;p&gt;由于这个包是外部依赖，没有加入中央仓库，所以只需要修改源码，重新编译。 进入umeng.api.client.java.biz-sources.jar，删除其中fastjson，重新打包即可。&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 03 Mar 2023 02:54:00 GMT</pubDate>
    </item>
    <item>
      <title>docker磁盘清理</title>
      <link>https://gitlab.520531.xyz/article/docker-overlay2-storage-too-large</link>
      <content:encoded>&lt;p&gt;磁盘查看&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;df -h &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;docker日志文件大小查看&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;ls -lh $(find /var/lib/docker/containers/ -name *-json.log) &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;查找大文件&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;find / -type f -size +100M &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;列出当前目录下的文件大小&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;du -sh * &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;查看所有文件，包含隐藏文件&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;du -sh * .[^.]* &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;清理docker缓存，overlay2过大&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;docker system prune -f &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;谨慎使用 docker system prune -a&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 04 Jan 2023 07:15:00 GMT</pubDate>
    </item>
    <item>
      <title>ElementUI的tree转换为Map结构</title>
      <link>https://gitlab.520531.xyz/article/element-tree-convert-to-map</link>
      <content:encoded>&lt;p&gt;Element的树结构，转换为java的map结构，同时父子结构相同&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;    public static void main(String[] args) {         String jsonStr = FileUtil.readUtf8String(&amp;quot;C:\\Users\\Administrator\\Desktop\\json.txt&amp;quot;);         JSONObject jo = (JSONObject) JSON.parseArray(jsonStr).get(0);         JSONArray children = jo.getJSONArray(&amp;quot;children&amp;quot;);         Map&amp;lt;String, Object&amp;gt; map = new HashMap&amp;lt;&amp;gt;();         List&amp;lt;JSONObject&amp;gt; collect = children.stream().map(a-&amp;gt;(JSONObject)a).collect(Collectors.toList());         for (JSONObject jsonObject : collect) {             sub(map,jsonObject);         }         System.out.println(JSON.toJSONString(map,true));     }      private static void sub(Map map,JSONObject child){             String type = child.getString(&amp;quot;type&amp;quot;);//node / param             String key;             if (type.equals(&amp;quot;node&amp;quot;)) {                 key = child.getString(&amp;quot;label&amp;quot;);                 Map&amp;lt;String, Object&amp;gt; tMap = new HashMap&amp;lt;&amp;gt;();                 map.put(key,tMap);                 List&amp;lt;JSONObject&amp;gt; collect  = child.getJSONArray(&amp;quot;children&amp;quot;).stream().map(a-&amp;gt;(JSONObject)a).collect(Collectors.toList());                 for (JSONObject jsonObject : collect) {                     sub(tMap, jsonObject);                 }             }else{                 JSONObject endPoint = child.getJSONObject(&amp;quot;endPoint&amp;quot;);                 key = endPoint.getString(&amp;quot;name&amp;quot;);                 Object value = endPoint.get(&amp;quot;defaultValue&amp;quot;);                 map.put(key,value);             }     } &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Tue, 06 Sep 2022 07:42:00 GMT</pubDate>
    </item>
    <item>
      <title>java使用handlebars模板，中文变量导致编译失败的替代处理方案</title>
      <link>https://gitlab.520531.xyz/article/handlebars-chinese-syntat-error</link>
      <content:encoded>&lt;p&gt;近期需要集成多个模板引擎，其中就包括handlebars，笔者根据热度，选择了开源的https://github.com/jknack/handlebars.java 作为依赖，但无奈却无法编译如下代码&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;Handlebars handlebars = new Handlebars(); Template template = handlebars.compileInline(&amp;quot;Hello {{测试}}!&amp;quot;); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;大致翻看了git上的issue，以及部分源码，发现确实有此问题，似乎该库也以及久未维护。时间有限，也不能详细调试源码，所以就打算，使用java调用js引擎（js可编译中文）来完成。直接上代码&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import org.springframework.stereotype.Component;  import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import java.io.File; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Map; import java.util.concurrent.ThreadPoolExecutor;  /**  * @author xiatiao  * @description handlebars js模板实现  * @date 2022/9/5  */ @Component public class HandlebarsTemplateJSConvert implements TemplateConvert {      //脚本引擎     private static ScriptEngine scriptEngine;      //js引擎是否加载     private volatile boolean engineLoaded = false;      //对象锁     Object lock = new Object();      @Resource     ThreadPoolExecutor threadPoolExecutor;      @PostConstruct     public void init() {         //忽略告警         System.setProperty(&amp;quot;nashorn.args&amp;quot;, &amp;quot;--no-deprecation-warning&amp;quot;);         //不阻塞主线程-加载脚本         Thread thread = new Thread(() -&amp;gt; {             try {                 //js引擎                 ScriptEngineManager scriptEngineManager = new ScriptEngineManager();                 scriptEngine = scriptEngineManager.getEngineByName(&amp;quot;javascript&amp;quot;);                 InputStream inputStream = HandlebarsTemplateJSConvert.class.getResourceAsStream(&amp;quot;/handlebars.js&amp;quot;);                 String jsContent = IoUtil.read(inputStream, StandardCharsets.UTF_8);                 InputStream helperInputStream = HandlebarsTemplateJSConvert.class.getResourceAsStream(&amp;quot;/helpers-handlebars.js&amp;quot;);                 String helperContent = IoUtil.read(helperInputStream, StandardCharsets.UTF_8);                 scriptEngine.eval(jsContent);                 scriptEngine.eval(helperContent);                 engineLoaded = true;                 synchronized (lock) {                     //激活等待线程                     lock.notifyAll();                 }             } catch (ScriptException e) {                 throw new RuntimeException(&amp;quot;加载handlebars脚本引擎异常&amp;quot;, e);             }         });         threadPoolExecutor.execute(thread);     }      @Override     public void convert(String templateDir, String templateFileName, String targetDir, String outFileName, Map param) throws Throwable {         String templateStr = FileUtil.readUtf8String(templateDir + File.separator + templateFileName);         String resultString = jsConvert(templateStr, param);         FileUtil.writeString(resultString, targetDir + File.separator + outFileName, StandardCharsets.UTF_8);     }      private String jsConvert(String template, Map param) throws Throwable {         //引擎加载结束以前线程等待         if (!engineLoaded) {             try {                 synchronized (lock) {                     lock.wait();                 }             } catch (InterruptedException e) {                 e.printStackTrace();             }         }         String jsonParam = JSON.toJSONString(param);         // 执行函数名         String functionName = &amp;quot;loadMe&amp;quot;;         Invocable invocable = (Invocable) scriptEngine;         //Object eval = scriptEngine.eval(&amp;quot;loadMe(&amp;quot;{{a}}&amp;quot;,{a:1})&amp;quot;);         Object result = invocable.invokeFunction(functionName, template, jsonParam);         return result.toString();     }  } &lt;/code&gt;&lt;/pre&gt; &lt;pre&gt;&lt;code class="language-java"&gt;/**  * 模板接口  * @author xiatiao  * @date 2022/9/5  */ public interface TemplateConvert {      /**      * @description      * @param templateDir 模板目录      * @param templateFileName 模板文件名称      * @param targetDir 输出目录      * @param outFileName 输出文件名称      * @param param 参数      * @author xiatiao      * @date 2022/9/5      */     void convert(String templateDir, String templateFileName,String targetDir ,String outFileName, Map param) throws Throwable;  } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;笔者这里要实现多种模板，所以抽象了一个接口，规范接口的调用方式。&lt;/p&gt; &lt;p&gt;文中使用的handlebars.js， 下载地址：https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.js&lt;/p&gt; &lt;p&gt;helpers-handlebars.js文件内容如下：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;function loadMe(templateStr,jsonStr){     var jsonObject = JSON.parse(jsonStr);     var template = Handlebars.compile(templateStr);     var result = template(jsonObject);     return result; } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;文件都保存到resources目录下即可。&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 06 Sep 2022 07:11:00 GMT</pubDate>
    </item>
    <item>
      <title>为什么网站要用https，怎么提高https的访问速度</title>
      <link>https://gitlab.520531.xyz/article/https-my-opinion</link>
      <content:encoded>&lt;p&gt;http和https，这两个词对于外行来说，大多是不知道这俩区别的，即使在程序开发的圈内，依然有很多小伙伴不清楚这俩有什么不一样。&lt;/p&gt; &lt;p&gt;https其实就是http over tls的简称，tls相当于建立的一条加密的隧道，http则是隧道里面的流动的内容。 至于tls怎么实现加密的，这里就不赘述了，你只需要知道，&lt;strong&gt;tls是一条加密的隧道&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;10年前，几乎大多数的网站，都是使用的http协议，而http是明文协议。这也就意味着，发送一个http请求，在任何能获取到流量的地方，都可以获取到发送的内容，当然也可以获取到网站的返回内容。从信息安全的角度来说，这种流量有被窥探，以及篡改的风险。&lt;/p&gt; &lt;p&gt;为了解决流量的安全问题，人们发明了https协议，让不加密的http流量跑在加密的tls通道里。这样，如果要窥探内容，那么就需要对tls进行解密。当然，目前来说，http使用的证书机制还是相对比较安全的。&lt;/p&gt; &lt;p&gt;我们返回来再说流量安全，当你再浏览器打上baidu.com，回车时，首先，baidu.com需要发给dns服务器解析，当本地没有缓存该域名，或者缓存过期，那么这个dns请求就会发送到dns服务器上，而dns请求是一个明文请求，此时就可能产生了第一次的信息泄露&lt;/p&gt; &lt;h3&gt;&lt;strong&gt;链路中间任何一个路由，交换设备都可以知道你要访问baidu&lt;/strong&gt;&lt;/h3&gt; &lt;p&gt;dns服务器收到这个请求后，会返回给你该域名指向的ip地址，以及该ip的有效时间（ttl）。此时浏览器就会和该ip地址建立http连接，发送请求的数据，此时交换的任何数据，再http协议下，对沿途的设备都是透明的，这样就又会产生第二次信息泄露风险&lt;/p&gt; &lt;h3&gt;&lt;strong&gt;链路中间任何一个路由，交换设备都可以知道你和百度交换的内容&lt;/strong&gt;&lt;/h3&gt; &lt;p&gt;对于第一个问题，似乎我们没有很好的解决方案，只能寄希望于Doh（dns over tls）的普及，而第二个问题，则正好可以通过https来解决数据传输的加密。&lt;/p&gt; &lt;p&gt;仅仅这样就结束了？当然不是，其实我们平时上网，比如百度，我们甚至只会打 baidu.com就提交了，浏览器会默认添加上http协议，当百度发现这个http请求不安全的时候，他会给你返回一个301永久转跳，或者302临时转跳到https://baidu.com ,对于我们自己的网站，则一般在头信息中加入hsts信息，只允许https访问即可，这样任何http都会被重定向到https。当然，这也是有代价的，任何一次重定向，都会进行一次网络io，而第一次访问该网站，这样的io看起来似乎是不可避免的。&lt;/p&gt; &lt;p&gt;于是浏览器组织发明了HSTS Preload list，其实就是一个域名名单，所有在这个名单中的域名，无论用户怎么输入，都会在浏览器发送阶段，直接变成https访问，也就少了服务器端的重定向。关于HSTS Preload list，更多的信息可以自行百度。&lt;/p&gt; &lt;p&gt;笔者的部落格在去年申请后，大概两个月后的浏览器版本中，加入了默认的HSTS Preload list。&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 22 Jun 2022 09:09:00 GMT</pubDate>
    </item>
    <item>
      <title>升级boot版本至2.6.x的更新之循环依赖</title>
      <link>https://gitlab.520531.xyz/article/circle-dependency-spring</link>
      <content:encoded>&lt;p&gt;前几天遇到一个问题，就是代码中产生了循环依赖，然后就报了以下异常&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;依稀还记得，一般这种A依赖B,B又依赖A的这种循环，spring通过bean的三级缓存，提前暴漏对象的方式已经解决了啊。仔细又读了一下报错信息，它说把 spring.main.allow-circular-references 设置成true也可以作为解决手段， 从这个属性的字面意思也可以看到，要把允许循环依赖设置为true即可解决，那么应该是spring在2.6.x的版本默认不允许循环依赖了。&lt;/p&gt; &lt;p&gt;解决方法1： 可以在bean上加上@Lazy注解，让bean延迟加载&lt;/p&gt; &lt;p&gt;解决方法2： 按照提示信息，配置文件中添加&lt;/p&gt; &lt;pre&gt;&lt;code class="language-yml"&gt;spring:   main:     allow-circular-references: true &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;当然如果能在业务层面较低成本打破循环依赖是最好的，如果成本较高，建议方案一。&lt;/p&gt; &lt;p&gt;如果既有代码升级boot版本，方案二也未尝不可。&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 03 Mar 2022 03:30:00 GMT</pubDate>
    </item>
    <item>
      <title>升级boot版本至2.6.x的变化之swagger</title>
      <link>https://gitlab.520531.xyz/article/boot-26x-swagger</link>
      <content:encoded>&lt;p&gt;由于近期springboot爆发了一系列高危漏洞，遂也决定把boot和其他一些依赖一并升级一下。升级后首先就是项目无法启动了，报错如下:&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;根据堆栈信息，应该是spring mvc处理程序映射匹配请求路径的默认策略已从 AntPathMatcher 更改为PathPatternParser,看来是springfox没有适配路径策略的问题，于是带着问题直接找到了springfox的github主页（ https://github.com/springfox/springfox/issues ），发现果然一堆关于升级2.6.x的issue，再看看项目基本两年多没更新了，看样子指望springfox更新适配2.6+暂时是不用指望了，临时的解决方案也比较暴力，通过反射获取到bean的属性，直接修改。 方法如下(通过bean的后置处理器)&lt;/p&gt; &lt;p&gt;修改yml&lt;/p&gt; &lt;pre&gt;&lt;code class="language-yml"&gt;spring:     mvc:     pathmatch:       matching-strategy: ANT_PATH_MATCHER #springfox未更新，和springboot2.6+冲突 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;添加一个bean的后置处理器（如果没有引入springboot的端点，这一步可以不要）&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;    @Override     public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {         if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {             List&amp;lt;RequestMappingInfoHandlerMapping&amp;gt; handlerMappings = getHandlerMappings(bean);             customizeSpringfoxHandlerMappings(handlerMappings);         }         return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);     }      private &amp;lt;T extends RequestMappingInfoHandlerMapping&amp;gt; void customizeSpringfoxHandlerMappings(List&amp;lt;T&amp;gt; mappings) {         List&amp;lt;T&amp;gt; copy = mappings.stream()                 .filter(mapping -&amp;gt; mapping.getPatternParser() == null)                 .collect(Collectors.toList());         mappings.clear();         mappings.addAll(copy);     }      @SuppressWarnings(&amp;quot;unchecked&amp;quot;)     private List&amp;lt;RequestMappingInfoHandlerMapping&amp;gt; getHandlerMappings(Object bean) {         try {             Field field = ReflectionUtils.findField(bean.getClass(), &amp;quot;handlerMappings&amp;quot;);             field.setAccessible(true);             return (List&amp;lt;RequestMappingInfoHandlerMapping&amp;gt;) field.get(bean);         } catch (IllegalArgumentException | IllegalAccessException e) {             throw new IllegalStateException(e);         }     } &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 03 Mar 2022 02:10:00 GMT</pubDate>
    </item>
    <item>
      <title>N1盒子在openwrt系统下偶尔断网的解决</title>
      <link>https://gitlab.520531.xyz/article/57</link>
      <content:encoded>&lt;p&gt;n1，63+o 固件在旁路由的模式下，偶尔会出现网络断开（有时两三天一次，有时一个月一次），按f大建议，降级到60+o，问题依然存在，简直不能愉快的玩耍。后来发现主路由（华硕）和旁路由(n1)同时重启，n1重启的快，华硕比较慢，此时一定是无法联网的，按openwrt坛友说法，是因为n1找不到主路由，无法创建网桥导致。但是不能每次都要等主路由重启完成了，再启动N1吧。加上以前也有偶尔断网问题，既然网上都没有解决方案（除了重启），遂决定自己动手。&lt;/p&gt; &lt;p&gt;进入n1的ssh，惊奇的发现不仅无法上网，光猫都ping不通，应该是网络服务出了问题，重启network服务试一下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;systemctl network restart &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;所有的设备居然全部可以上网了...既然这样那我就实现一个定时脚本，取ping光猫，如果到光猫不通，则说明网络肯定是出问题了，这时候就重启network即可。&lt;/p&gt; &lt;p&gt;新建脚本 resetNetWork.sh 内容如下：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt; #!/usr/bin/env bash  declare -g LOG LOG=&amp;quot;${0%/*}/check.log&amp;quot; ping -c 3 -w 100 192.168.1.1 if [[ $? != 0 ]];then       HEAD=$(printf '%(%Y-%m-%d %H:%M:%S)T\n' &amp;quot;-1&amp;quot; )  echo &amp;quot;===============fail========== $HEAD ========================&amp;quot; &amp;gt;&amp;gt; $LOG  /mnt/mmcblk2p2/etc/init.d/network restart else                     echo &amp;quot; ping ok&amp;quot;        fi &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后对以上脚本添加计划任务&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;*/1 * * * * bash /mnt/mmcblk2p4/myTask/resetNetWork.sh &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Sun, 06 Feb 2022 08:43:00 GMT</pubDate>
    </item>
    <item>
      <title>利用aop高效的实现字典，和外键属性的转译</title>
      <link>https://gitlab.520531.xyz/article/dict-translate-method</link>
      <content:encoded>&lt;p&gt;我们现在设计有如下两张表（其中，学生表位班级表的子表）&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;班级表（sys_class）: 属性：id name  head_teacher ...  学生表（sys_student） 属性：id class_id name gender ...  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;此时，我们有某个需求，需要查询学生，并且需要学生的班级名称。&lt;/p&gt; &lt;p&gt;我们一般的做法有以下几种：&lt;/p&gt; &lt;p&gt;(1). 使用sql的join来实现&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;select t1.*,t2.name as class_name from sys_student t1 left join sys_class t2 on t1.class_id= t2.id &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;join的本质还是创建了虚拟表，对结果做笛卡儿积。这是非常恐怖的，笛卡儿积会导致数据成倍增长，占用大量的资源，导致大幅降低数据库的吞吐量。&lt;/p&gt; &lt;p&gt;(2). 使用程序来实现关联 做法是先查询全部学生，再查询全部班级，使用两层for循环或者是使用map缓存班级id和班级名称的对应关系。总之，该方法所有逻辑处理均在代码中完成，数据库只提供基础的查询功能。&lt;/p&gt; &lt;p&gt;数据库是维持系统稳定的重要基础设施，大多数情况下，此方法比（1）中的方法要更优秀的，只需做简单的数据库io，这样数据库系统就能用节省下来的资源去支持更多的并发。缺点也很明显，相比第一种方式，需要编写代码来实现逻辑，尤其是复杂的系统，代码量可能更大。&lt;/p&gt; &lt;p&gt;笔者使用的是第三种方法，现在大多数的ORM框架都默认实现了单表的查询，在此基础上，笔者选择方法2，但是基于aop来实现关系字段的转译。&lt;/p&gt; &lt;p&gt;代码如下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Repeatable(DictS.class) public @interface Dict {      String dicTable(); //字典表      String dicText(); //字典表中需要翻译到的text      String dicColumn(); //字典表的列      String targetColumnName() default &amp;quot;&amp;quot;; //新增的列名，默认为{code}加上_text } &lt;/code&gt;&lt;/pre&gt; &lt;pre&gt;&lt;code class="language-java"&gt;@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface DictS {      Dict[] value();  }  &lt;/code&gt;&lt;/pre&gt; &lt;pre&gt;&lt;code class="language-java"&gt;/**  * @Description 注解翻译字典  * @since 2020-12-25  */ @Aspect @Component @Slf4j public class TranslateDictAspect {      @Resource     CommonApiService commonApiService;      @Resource     ObjectMapper objectMapper;      // 定义切点Pointcut     @Pointcut(&amp;quot;execution(public * com.trusted.software..*.*Controller.*(..))&amp;quot;)     public void executeService() {     }      @Around(&amp;quot;executeService()&amp;quot;)     public Object doAround(ProceedingJoinPoint pjp) throws Throwable {         MethodSignature signature = (MethodSignature) pjp.getSignature();         UnUseDict unUseDict = signature.getMethod().getAnnotation(UnUseDict.class);         if(unUseDict!=null){             return pjp.proceed();         }         long time1=System.currentTimeMillis();      //执行controller         Object result = pjp.proceed();         long time2=System.currentTimeMillis();         log.debug(&amp;quot;controller 耗时：&amp;quot;+(time2-time1)+&amp;quot;ms&amp;quot;);         long start=System.currentTimeMillis();         //翻译controller返回结果         try {             this.translate(result);         } catch (JsonProcessingException | JSONException e) {             //同时捕获jackson，fastjson 转换异常             //处理失败,静默原样返回             log.debug(&amp;quot;非json格式数据-&amp;gt;&amp;quot;,e);         }         long end=System.currentTimeMillis();         log.debug(&amp;quot;翻译  耗时&amp;quot;+(end-start)+&amp;quot;ms&amp;quot;);         return result;     }      /**      * TODO 批量转换      * @param result      * @throws IllegalAccessException      */     private void translate(Object result) throws JsonProcessingException {         if (result instanceof R) {             Object data = ((R) result).getData();             //处理集合             if(data instanceof Collection) {                 //这里处理一层集合                 Collection collection = (Collection)data;                 List&amp;lt;JSONObject&amp;gt; resultList = new ArrayList&amp;lt;&amp;gt;();                 for (Object obj : collection) {                     JSONObject item = handleItem(obj);                     resultList.add(item);                 }                 //数据回填                 ((R)result).setData(resultList);             }else{                 //分页数据                 if(data instanceof IPage){                     List records = ((IPage) data).getRecords();                     List&amp;lt;JSONObject&amp;gt; resultList = new ArrayList&amp;lt;&amp;gt;();                     for (Object obj : records) {                         JSONObject item = handleItem(obj);                         resultList.add(item);                     }                     //数据回填                     ((IPage) data).setRecords(resultList);                 }else {                     if(null!=data) {                         //非分页单条数据                         JSONObject item = handleItem(data);                         //数据回填                         ((R) result).setData(item);                     }                 }             }         }     }      public JSONObject handleItem(Object obj) throws JsonProcessingException {         String json=&amp;quot;{}&amp;quot;;         //使用ObjectMapper处理一遍-时间格式化问题         json = objectMapper.writeValueAsString(obj);         JSONObject item = JSONObject.parseObject(json);         Class&amp;lt;?&amp;gt; clazz = obj.getClass();         Field[] declaredFields = clazz.getDeclaredFields();         for (Field declaredField : declaredFields) {             if (declaredField.isAnnotationPresent(Dict.class)) {                 String fieldName = declaredField.getName();                 declaredField.setAccessible(true);                 Object value = null;                 try {                     value = declaredField.get(obj);                 } catch (IllegalAccessException e) {                     e.printStackTrace();                 }                 Dict dict = declaredField.getAnnotation(Dict.class);                 dicItem(dict,value,item,fieldName);             }else if (declaredField.isAnnotationPresent(DictS.class)){                 String fieldName = declaredField.getName();                 DictS dictS = declaredField.getAnnotation(DictS.class);                 Dict[] dicArr = dictS.value();                 for (Dict dict:dicArr) {                     declaredField.setAccessible(true);                     Object value = null;                     try {                         value = declaredField.get(obj);                     } catch (IllegalAccessException e) {                         e.printStackTrace();                     }                     dicItem(dict,value,item,fieldName);                 }             }         }         return item;      }      public void dicItem(Dict dict,Object value,JSONObject item,String fieldName){         String table = dict.dicTable();         String text = dict.dicText();         String column = dict.dicColumn();         String targetColumnName = dict.targetColumnName();         //此处做了reids缓存         DictModel dictModel = commonApiService.queryTableDictTextByKey(table, text, column, value);         if (dictModel!=null) {             String translatedText = dictModel.getText();             if(!StrUtil.isEmpty(targetColumnName)) {                 item.put(targetColumnName, translatedText);             }else{                 item.put(fieldName + &amp;quot;_text&amp;quot;, translatedText);             }         }     }    } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这样，我们在业务系统中，就可以只通过注解@Dict的方式，减少大量的代码。配合上aop，就实现了外键的转译。在实际开发中，还可以结合sql，查询vo，对vo再进行转译，大量降低子查询，join查询，使用起来是比较灵活的。&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 16 Dec 2021 02:05:00 GMT</pubDate>
    </item>
    <item>
      <title>2020之后openfeign自定义负载均衡规则</title>
      <link>https://gitlab.520531.xyz/article/springcloud2020-openfeign-loadbalance</link>
      <content:encoded>&lt;p&gt;负载均衡的方式有很多，从客户端负载均衡，dns负载均衡，到服务器端负载均衡，均有所属的细分领域。本文仅仅探讨openfeign作为服务端的消费方，对服务提供者的负载均衡。&lt;/p&gt; &lt;p&gt;cloud2020版本之前，要修改openfeign默认的负载均衡方式比较简单，openfeign在负载均衡选择服务提供者时，会使用LoadBalancerClient（netflix）通过IRule这个这个接口来choose服务器，所以我们也只需要自定义一个IRule，用以替换默认的IRule实例即可，当然默认IRule也有很多实现，按需选择即可。当然我们也完全可以重新定义一个LoadBalancerClient 直接覆盖原有实例，或者在BeanPostProcessor对象后置处理器覆盖，都是可以的。spring也因为提供了这么强大的扩展性而长盛不衰。最后，不要忘了注入ioc容器。&lt;/p&gt; &lt;p&gt;本次重点来说2020版之后，LoadBalancerClient（netflix）也不存在，取而代之的是LoadBalancerClient（cloud），不管代码如何变，我们处理问题的思路基本不变，也就是万变不离其宗，我们一样重写 LoadBalancerClient 中的choose方法即可。不过新版的实现类只有BlockingLoadBalancerClient 这一个了。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;    @Bean     @Primary     public LoadBalancerClient blockingLoadBalancerClient(ReactiveLoadBalancer.Factory&amp;lt;ServiceInstance&amp;gt; loadBalancerClientFactory){         LoadBalancerClient blockingLoadBalancerClient = new BlockingLoadBalancerClient(loadBalancerClientFactory){             @Override             public &amp;lt;T&amp;gt; ServiceInstance choose(String serviceId, Request&amp;lt;T&amp;gt; request) {                 ReactiveLoadBalancer&amp;lt;ServiceInstance&amp;gt; loadBalancer = loadBalancerClientFactory.getInstance(serviceId);                 if (loadBalancer == null) {                     return null;                 } else {                     List&amp;lt;ServiceInstance&amp;gt; instances = discoveryClient.getInstances(serviceId);                     //这就是修改负载均衡策略，获取不同实例的地方                     //下面被注释掉的return就是默认的轮询方式                     return  instances.get(0); //                    Response&amp;lt;ServiceInstance&amp;gt; loadBalancerResponse = (Response) Mono.from(loadBalancer.choose(request)).block(); //                    return loadBalancerResponse == null ? null : (ServiceInstance)loadBalancerResponse.getServer();                 }             }         };         return  blockingLoadBalancerClient;     };  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;笔者本次修改负载均衡策略主要是为了使用把用户hash到相对固定的主机上，使用jvm缓存的目的。只需要获取到用户名，计算hash，然后对服务长度取余即可。&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 13 Aug 2021 01:45:00 GMT</pubDate>
    </item>
    <item>
      <title>oracleJDK 11切换到 openJDK 可行吗</title>
      <link>https://gitlab.520531.xyz/article/openjdk11-switch</link>
      <content:encoded>&lt;p&gt;Oracle高级顾问原文:&lt;a href="https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later" target="_blank"&gt;https://blogs.oracle.com/java/post/oracle-jdk-releases-for-java-11-and-later&lt;/a&gt; 答案是可以切换，而且代码基本一致，区别主要一些外观装饰性的，比如javafx。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;Functionally identical and interchangeable... &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;结论是功能相同，且可互换。当然，这是在不用到那些装饰性特性的情况。一般的java项目，spring项目，亲测无问题。&lt;/p&gt; &lt;p&gt;至于为什么要切换，当然是避免商业授权问题。&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 21 Feb 2021 03:47:00 GMT</pubDate>
    </item>
    <item>
      <title>Docke记录</title>
      <link>https://gitlab.520531.xyz/article/55</link>
      <content:encoded>&lt;p&gt;&lt;strong&gt;时区修改&lt;/strong&gt; csdn有很多教程，但基本貌似抄的同一个人的，基本不能用，这里记录一下， Dockerfile中添加如下命令，localtime文件使用软连接，timezone文件直接覆盖&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime &amp;amp;&amp;amp; echo &amp;quot;Asia/Shanghai&amp;quot; &amp;gt; /etc/timezone &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;idea下docker的log中文乱码&lt;/strong&gt; 只需修改idea的启动参数，添加以下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;-Dfile.encoding=utf-8 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Fri, 13 Nov 2020 08:03:00 GMT</pubDate>
    </item>
    <item>
      <title>使用tomcat线程池代替jdk线程池处理io密集型任务</title>
      <link>https://gitlab.520531.xyz/article/tomcat-thread-pool-mark</link>
      <content:encoded>&lt;h1&gt;&lt;strong&gt;J.U.C线程池&lt;/strong&gt;&lt;/h1&gt; &lt;p&gt;JDK的J.U.C包下线程池处理比较适合处理cpu密集型任务，另外，由于线程调度逻辑上，线程提交逻辑是 core-&amp;gt;queue-&amp;gt;max-&amp;gt;reject 这样的处理逻辑导致有两个缺点：&lt;/p&gt; &lt;ol&gt; &lt;li&gt;max设置很多时候显得可有可无，因为只有当队列满了才会调用max创建临时worker&lt;/li&gt; &lt;li&gt;面对突发性高流量(未到达队列上限)，固定的coreSize，线程数量的伸缩性显得有些呆板&lt;/li&gt; &lt;/ol&gt; &lt;h1&gt;&lt;strong&gt;tomcat线程池&lt;/strong&gt;&lt;/h1&gt; &lt;p&gt;tomcat线程池正是针对以上问题的优化，用于在高并发下，线程池具备更好的伸缩性而开发的。其中修改包括：执行拒绝策略后再尝试拯救一次线程，但最重要的改变就是重写了Queue。通过重写queue的offer方法，用来控制是否创建新的线程&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;    @Override     public boolean offer(Runnable o) {         //we can't do any checks         if (parent==null) {             return super.offer(o);         }         //we are maxed out on threads, simply queue the object         if (parent.getPoolSize() == parent.getMaximumPoolSize()) {             return super.offer(o);         }         //we have idle threads, just add it to the queue         if (parent.getSubmittedCount()&amp;lt;=(parent.getPoolSize())) {             return super.offer(o);         }         //if we have less threads than maximum force creation of a new thread         if (parent.getPoolSize()&amp;lt;parent.getMaximumPoolSize()) {             return false;         }         //if we reached here, we need to add it to the queue         return super.offer(o);     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;其中getSubmittedCount()获取的是已提交线程数，该值是AtomicInteger，每次提交线程时增加一，线程完成或者线程拒绝则减1。&lt;/p&gt; &lt;h1&gt;&lt;strong&gt;应用&lt;/strong&gt;&lt;/h1&gt; &lt;p&gt;线程在操作系统中也是轻量的进程，于系统而言，也是一种昂贵的资源，不能无节制的创建，销毁，否则线程的上下文切换将会导致操作系统在用户态和内核态频繁切换，最终系统中断消耗大量cpu资源，甚至资源耗尽。开发中如果需要处理高并发的io线程，就要像tomcat线程池一样具备很高的伸缩性，那我们也可以直接自己来创建tomcat线程池，用于自己的任务，创建方法如下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;//队列长度-当然设置成最大Integer是存在内存溢出风险的，根据业务调整 TaskQueue taskqueue = new TaskQueue(Integer.MAX_VALUE); /**  * param-1 线程名称  * param-2 是否守护线程  * param-3 优先级  */ TaskThreadFactory tf = new TaskThreadFactory(&amp;quot;my-pool-&amp;quot;,true, Thread.NORM_PRIORITY); ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 60000, TimeUnit.MILLISECONDS,taskqueue, tf); //这句千万不能少,否则不会调用TaskQueue的offer，原因见本文前部分源码 taskqueue.setParent(executor); &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Fri, 06 Nov 2020 07:55:00 GMT</pubDate>
    </item>
    <item>
      <title>利用openssl自签ssl证书</title>
      <link>https://gitlab.520531.xyz/article/openssl-self-signed-ca</link>
      <content:encoded>&lt;p&gt;1.生成私钥key&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl genrsa -out server.key 1024 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;2.根据私钥生成证书申请文件csr&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl req -new -key server.key -out server.csr &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;根据向导输入即可，注意其中一项 Common Name (e.g. server FQDN or YOUR name) [],这个建议输入自己的域名或者ip,当然随便写也可以&lt;/p&gt; &lt;p&gt;3.使用私钥对证书申请进行签名从而生成证书&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 365 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;其中-days 后面跟的是有效天数，从当前时间起算 开启tcp over ssl，使用自签ssl可以从一定程度上解决http明文传播的问题。&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 07 May 2020 03:11:00 GMT</pubDate>
    </item>
    <item>
      <title>java实现socket代理执行shell获取返回值，程序发生的进化</title>
      <link>https://gitlab.520531.xyz/article/shell-proxy-issue</link>
      <content:encoded>&lt;p&gt;第一次代码是这样的&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;    static String interpreter = &amp;quot;/bin/sh&amp;quot;;      public static String runSimpleCommand(String command) throws IOException {         String[] cmd = {interpreter,&amp;quot;-c&amp;quot;,command};         Process process = Runtime.getRuntime().exec(cmd);         String result = RuntimeUtil.getResult(process);         return result;     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;一般情况下，以上代码执行是没有问题的，执行命令，读取返回结果。 但是如果命令执行过程中异常了，或者进程不止写了标准输出，还有标准错误输出，那么RuntimeUtil.getResult(process)将无法读取到错误信息，于是程序变成了下面这样。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;    public static ShellResult runSimpleCommand(String command) throws IOException {         String[] cmd = {interpreter,&amp;quot;-c&amp;quot;,command};         Process process = Runtime.getRuntime().exec(cmd);         String stdout = RuntimeUtil.getResult(process);         String stderr = RuntimeUtil.getErrorResult(process);         return new ShellResult(stdout,stderr);     }      @Data     @AllArgsConstructor     public class ShellResult{         private String stdout;         private String stderr;         public String std(){             return this.stdout+&amp;quot;\r\n&amp;quot;+this.stderr;         }     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这时又出现了问题，代码居然执行抛出了异常！ debug后才发现，hutool的RuntimeUtil获取返回值源码是这样的&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;      public static String getResult(Process process, Charset charset) {   InputStream in = null;   try {    in = process.getInputStream();    return IoUtil.read(in, charset);   } finally {    IoUtil.close(in);    destroy(process);   }  } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;原来hutool这货在读取结果后居然字节关闭流，destroy了这个process，难怪会抛异常。还是太相信这些工具类了，难道hutool的开发者就没想过，有些时候还需要同时读stderr吗。既然发现了问题。那这次就来自己实现流的读取，这里没有使用一次性读取inputstream，而是使用按行读取原因是因为业务需要，需要把标准输出过程数据写入远端socket中，这里代码就略去了。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;     public ShellResult runSimpleCommand(String command) throws IOException {         String[] cmd = {interpreter,&amp;quot;-c&amp;quot;,command};         Process process = Runtime.getRuntime().exec(cmd);         BufferedReader processBr = new BufferedReader(new InputStreamReader(process.getInputStream(), &amp;quot;utf-8&amp;quot;));         BufferedReader processErrorBr = new BufferedReader(new InputStreamReader(process.getErrorStream(), &amp;quot;utf-8&amp;quot;));         String processLine;         //--标准输出         StringBuilder stdout = new StringBuilder();         try {             while ((processLine = processBr.readLine()) != null) {                 stdout.append(processLine+&amp;quot;\r\n&amp;quot;);             }         } catch (IOException e) {             log.debug(&amp;quot;读stdout异常&amp;quot;,e);         }         //--标准err输出         StringBuilder stderr = new StringBuilder();         try {             while ((processLine = processErrorBr.readLine()) != null) {                 stderr.append(processLine+&amp;quot;\r\n&amp;quot;);             }         } catch (IOException e) {             log.debug(&amp;quot;读stderr异常&amp;quot;,e);         }         ShellResult shellResult = new ShellResult(stdout.toString(), stderr.toString());         return shellResult;     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;如果业务不需要过程输出，只要结果的话，当然文件流的长度是可预见的，直接读取效率更高，见代码。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;public static byte[] readBytes(InputStream in, boolean isClose) throws IOException {  // 文件流的长度是可预见的，此时直接读取效率更高  final byte[] result;  try {   final int available = in.available();   result = new byte[available];   final int readLength = in.read(result);   if (readLength != available) {    throw new IOException(StrUtil.format(&amp;quot;File length is [{}] but read [{}]!&amp;quot;, available, readLength));   }  } finally {   if (isClose) {    close(in);   }  }  return result; } &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;后记&lt;/h1&gt; &lt;p&gt;期间报错，一度以为process获取标准输出也是通过读取/proc/{pid}/fd/1这个文件，以为命令执行时间太短，导致读取完stdout后，进程销毁导致无法读取stderr，还把读取方式一度改为并发读取。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;    public ShellResult runSimpleCommandMultiGetResult(String command) throws IOException {         String[] cmd = {interpreter,&amp;quot;-c&amp;quot;,command};         Process process = Runtime.getRuntime().exec(cmd);         String result = &amp;quot;&amp;quot;;         String errors = &amp;quot;&amp;quot;;         Callable&amp;lt;String&amp;gt; resultCall = () -&amp;gt; {             String result1 = RuntimeUtil.getResult(process);             return result1;         };         Callable&amp;lt;String&amp;gt; errorsCall = () -&amp;gt; {             String errors1 = RuntimeUtil.getErrorResult(process);             return errors1;         };         FutureTask&amp;lt;String&amp;gt; resultTask = new FutureTask&amp;lt;&amp;gt;(resultCall);         FutureTask&amp;lt;String&amp;gt; errorResultTask = new FutureTask&amp;lt;&amp;gt;(errorsCall);         socketPool.submit(resultTask);         socketPool.submit(errorResultTask);         try {             result = resultTask.get();         } catch (Exception e) {             log.debug(&amp;quot;读stdout异常&amp;quot;,e);         }         try {             errors = errorResultTask.get();         } catch (Exception e) {             log.debug(&amp;quot;读stderr异常&amp;quot;,e);         }         ShellResult shellResult = new ShellResult(result, errors);         return shellResult;     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;其实在这个process对象没有被销毁，流没有关闭的情况下，一直都可以读取，读取流的方式也不是通过读取pid下的文件。&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 30 Apr 2020 09:12:00 GMT</pubDate>
    </item>
    <item>
      <title>arthas用法记录</title>
      <link>https://gitlab.520531.xyz/article/arthas-command-useful</link>
      <content:encoded>&lt;p&gt;&lt;strong&gt;arthas watch对于重载的用法&lt;/strong&gt;&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;watch com.ixiatiao.Test getUserInfo params &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;可能会匹配到多个方法(方法重载)&lt;br /&gt; 那么如何准确匹配到具体方法呢，可以使用两种方式&lt;br /&gt; 1.根据参数个数匹配&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;watch com.ixiatiao.Test getUserInfo params params.length==3  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;2.根据参数类型匹配&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;watch com.ixiatiao.Test getUserInfo params 'params[0].class.name==&amp;quot;java.lang.String&amp;quot;' &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;（注：如果是基本类型，这里要使用包装类型，如int-&amp;gt;java.lang.Intager）&lt;/p&gt; &lt;hr /&gt;</content:encoded>
      <pubDate>Fri, 20 Dec 2019 02:15:00 GMT</pubDate>
    </item>
    <item>
      <title>java异常处理的艺术</title>
      <link>https://gitlab.520531.xyz/article/java-backend-exception-handler</link>
      <content:encoded>&lt;p&gt;笔者曾经接触过俗称的shi山项目，代码中满篇的try-catch，有次测试人员发现qa有数据不对，遂提出bug，我们这里的开发人员翻取k8s的日志，死活没有找到报错信息，貌似程序全部正常，但却产生了非正常的数据。于是这名开发人员找到了我。不看不知道，一看吓一跳，service，controller，几乎所有方法都套上了try-catch，最最关键的是，catch的是Exception，之后居然什么也没干，甚至异常打印都没有，继续往下走。&lt;/p&gt; &lt;p&gt;能写出这种代码的人，我相信还是少数，大部分人起码不会无脑处理所有异常。在系统开发中，不合时宜的处理异常，不合时宜的抛出异常还是比较常见的。同时不当，不合时宜的异常处理也会给系统带来灾难。&lt;/p&gt; &lt;p&gt;要弄清异常怎么处理，我们就要弄明白异常是怎么产生的，处理的目的是什么。 异常可能来源于外部调用，比如读写文件，读写流，都会抛出io异常，也可能来源于代码本身，比如NPE，再比如我们期望值和实际值不相同，这时我们可能会主动抛出异常，合理的利用好断言，可以极大的提升自己代码的健壮性，以及代码的整洁度。&lt;/p&gt; &lt;p&gt;那么我们对这些异常应该怎么办呢?其实这个问题也没有标准答案，需要结合自己的具体情况。 举个栗子，我们要读取文件a.txt来获取内容，并且复制给变量b。 此时如果a.txt文件不存在，那就会抛出not found异常。&lt;/p&gt; &lt;p&gt;但是这个异常是否处理则需要看具体情况，假设a.txt这个文件很重要，读取不到其中的值，那这程序就走不下去了，那么此时则不应该吞下这个异常，最好的处理方式就是捕获异常，并且抛出自己的封装异常，给出友好提示。&lt;/p&gt; &lt;p&gt;若a.txt这个文件不重要，如果读取不到的话，我们就可以给b一个默认值，此时就可以捕获异常，在异常 中打入debug日志，并且给b一个默认值即可。&lt;/p&gt; &lt;p&gt;一般情况，service中的异常都是需要往外抛的，抛给调用方。controller中一般也不处理异常，把异常都抛到外面的异常拦截器里统一处理。如果遇到需要处理的异常，则要符合最小捕获原则，比如抛出的是IllegalAccessException，千万不要catch父类Exception。很可能处理了其他异常。&lt;/p&gt; &lt;p&gt;合理的利用异常，以及断言，会让你的代码看起来很简洁清爽，而且健壮。&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 10 Nov 2019 08:18:00 GMT</pubDate>
    </item>
    <item>
      <title>maven打包报错</title>
      <link>https://gitlab.520531.xyz/article/maven-package-error-01</link>
      <content:encoded>&lt;p&gt;运行 mvn package 命令报错&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project xxx &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;这个项目一直是可以编译通过的，突然打包失败，也是很意外，检查了idea设置的jdk版本，和编译器版本，全部都是正常的。&lt;/p&gt; &lt;p&gt;通过mvn -x package 输出详细的报错信息，其中有一句&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.code.TypeTags &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;最后确认这是因为lombok版本太低导致，更换新版本lombok后打包正常。&lt;/p&gt; &lt;p&gt;后续：通过cmd命令 输入java -version 显示是1.8 输入echo %JAVA_HOME%，发现居然是java11，原来是最近安装了jdk11覆盖了JAVA_HOME变量，经过检查mvn.cmd文件，果然取值是JAVA_HOME,这样问题就得到了解释，由于lombok老版本不支持java11导致的打包失败。那解决方案也就很明显了，要么改掉环境变量，要么升级lombok。当然jdk版本升级是需要考虑多种因素的，笔者这里就直接更改环境变量即可。&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 08 Oct 2019 13:25:00 GMT</pubDate>
    </item>
    <item>
      <title>shiro-redis下管理员怎么查看用户是否在线</title>
      <link>https://gitlab.520531.xyz/article/shiro-redis-online-check</link>
      <content:encoded>&lt;p&gt;背景是这样的，项目目前的用户session存储在redis中，使用了shiro-redis这个插件。最近有个需求，需要查看用户在线状态，就需要用到shiro-redis这个插件去读取在线的用户，但是却发现其代码久未更新，依然使用旧版本的jedis（2.9），但是项目中也使用了spring—data-redis，其中引用的jedis（3.7.1）和代码版本不匹配，导致无法使用，&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;scanResult.getStringCursor() &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;jedis中方法已变更为 getCursor(),现在解决办法有以下3种：&lt;/p&gt; &lt;ol&gt; &lt;li&gt; &lt;p&gt;下载shiro-redis源码，修改依赖以及错误代码，手动编译&lt;/p&gt; &lt;/li&gt; &lt;li&gt; &lt;p&gt;降低jedis版本至2.9。可能引发redis的其他问题，暂不可取。&lt;/p&gt; &lt;/li&gt; &lt;li&gt; &lt;p&gt;重写redisConfiguration中创建RedisManager的方法&lt;/p&gt; &lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code class="language-java"&gt;RedisManager redisManager = new RedisManager(){             //重写方法解决shiro-redis未更新jedis版本导致的异常             @Override             public Set&amp;lt;byte[]&amp;gt; keys(byte[] pattern) {                 Set&amp;lt;byte[]&amp;gt; keys = new HashSet&amp;lt;byte[]&amp;gt;();                 Jedis jedis = getJedis();                 try {                     ScanParams params = new ScanParams();                     params.count(super.getCount());                     params.match(pattern);                     byte[] cursor = ScanParams.SCAN_POINTER_START_BINARY;                     ScanResult&amp;lt;byte[]&amp;gt; scanResult;                     do {                         scanResult = jedis.scan(cursor, params);                         keys.addAll(scanResult.getResult());                         cursor = scanResult.getCursorAsBytes();                     } while (scanResult.getCursor().compareTo(ScanParams.SCAN_POINTER_START) &amp;gt; 0);                 } finally {                     jedis.close();                 }                 return keys;             }         }; &lt;/code&gt;&lt;/pre&gt; &lt;ol start="4"&gt; &lt;li&gt;使用spring-data-redis的lettuce连接池获取&lt;/li&gt; &lt;/ol&gt; &lt;pre&gt;&lt;code class="language-java"&gt; public Set&amp;lt;Integer&amp;gt; getOnlineUserIds() {         Object cached = redisService.get(RedisConstant.onlineUserIds);         if(null!=cached){             return (Set&amp;lt;Integer&amp;gt;) cached;         }         //获取全部登陆的用户缓存key         Set&amp;lt;String&amp;gt; keys = redisService.keys(RedisConstant.shiroSessionKey+&amp;quot;*&amp;quot;);         //读取redis已登陆的用户并且收集其ID         Set&amp;lt;Integer&amp;gt; onlineUserIds = keys.stream().map(key -&amp;gt; {             //直接从LettuceConnectionFactory读取             byte[] bytes = lettuceConnectionFactory.getConnection().get(key.getBytes());             //反序列化对象             SimpleSession session =  ObjectUtil.deserialize(bytes);             //从session中取到登陆的用户信息             SimplePrincipalCollection attribute = (SimplePrincipalCollection) session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);             User cu = (User) attribute.getPrimaryPrincipal();             return cu.getId();         }).collect(Collectors.toSet());         //手动缓存         redisService.set(RedisConstant.onlineUserIds,onlineUserIds,60);         return onlineUserIds;     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;当然笔者最终选择采用的是第四种方法，也可以比较方便的获取在线用户，并且对数据实现缓存以减少io。&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 01 Sep 2019 07:58:00 GMT</pubDate>
    </item>
    <item>
      <title>记一次青龙下的bark通知失败的处理</title>
      <link>https://gitlab.520531.xyz/article/ql-bark-fail</link>
      <content:encoded>&lt;p&gt;青龙下的bark通知如果太长，会发生失败的情况。通过阅读源码可知，发送bark消息默认使用的是get请求，但是get请求可以携带的信息有长度限制，这时候就需要把请求方式修改为post。&lt;/p&gt; &lt;p&gt;修改sendNotify代码如下&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;function BarkNotify(text, desp, params = {}) {   return new Promise((resolve) =&amp;gt; {     if (BARK_PUSH) {       const options = {         url: `${process.env.BARK_HOST}/push`,         json: {             title: text,             body: desp,             level: 'passive',             group: 'QingLong',             icon: `${BARK_ICON}`,             sound: `${BARK_SOUND}`,             device_key: `${process.env.BARK_TOKEN}`         },         headers: {           'Content-Type': 'application/json; charset=utf-8',         },         timeout,       };       $.post(options, (err, resp, data) =&amp;gt; {         try {           if (err) {             console.log('Bark APP发送通知调用API失败！！\n');             console.log(err);           } else {             data = JSON.parse(data);             if (data.code === 200) {               console.log('Bark APP发送通知消息成功🎉\n');             } else {               console.log(`${data.message}\n`);             }           }         } catch (e) {           $.logErr(e, resp);         } finally {           resolve();         }       });     } else {       resolve();     }   }); } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;现在这样是可以发送长消息的。但是每次执行完ql repo之后，以上的修改又会被覆盖掉。经过在原作者GitHub库回答的issue得知，默认会拷贝青龙容器中 /ql/deps 到所有其他的repo中，这样问题就简单了，用以上方法，修改/ql/deps/sendNotify.js即可。&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 23 Aug 2019 02:16:00 GMT</pubDate>
    </item>
    <item>
      <title>替换linux下的默认的jdk</title>
      <link>https://gitlab.520531.xyz/article/replace-jdk-linux</link>
      <content:encoded>&lt;p&gt;最近由于环境原因，必须要在linux下运行一些程序，但是服务器上jdk是默认的1.8，而我当前所用的是jdk11，于是就在服务器上也安装了11版本的jdk，但是java -version发现并没有切换，又不想在启动脚本的地方export jdk或者直接切到jdk目录运行。 切换方法（前提是已经安装了要切换的jdk）&lt;/p&gt; &lt;pre&gt;&lt;code class="language-shell"&gt;update-alternatives --config java &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Mon, 15 Jul 2019 08:03:00 GMT</pubDate>
    </item>
    <item>
      <title>docker开启远程访问后引发的安全问题</title>
      <link>https://gitlab.520531.xyz/article/56</link>
      <content:encoded>&lt;p&gt;docker直接在公网开启2375端口远程访问，虽然很大程度方便我们的开发到部署，但也引发了一系列安全问题。出于懒惰和侥幸，没有配置tls，结果开通2375端口的第二天，就发现服务器响应延迟变大很多，随即通过htop命令查看资源占用情况，发现cpu，内存均已满载，经过查证是个挖矿进程。果然通过docker image ls命令发现了异常的镜像，但是容器已经被删除。&lt;/p&gt; &lt;p&gt;由此可见，病毒程序不仅是通过2375直接部署在docker容器内，更可以通过其他方式感染宿主机器！docker本身并不支持用户名密码这种认证的，笔者也是采用的tls认证的方式。&lt;/p&gt; &lt;h1&gt;第一步 生成证书：&lt;/h1&gt; &lt;p&gt;1 创建一个目录用于存储生成的证书和秘钥&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;mkdir /docker-ca &amp;amp;&amp;amp; cd /docker-ca  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;2 创建CA证书私钥，期间需要输入两次密码，生成文件为ca-key.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl genrsa -aes256 -out ca-key.pem 4096  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;3 根据私钥创建CA证书，期间需要输入上一步设置的私钥密码，然后依次输入国家是 CN，省例如是Guangdong、市Shenzhen、组织名称、组织单位、姓名或服务器名、邮件地址，都可以随意填写，生成文件为ca.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;4 创建服务端私钥，生成文件为server-key.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl genrsa -out server-key.pem 4096 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;5 创建服务端证书签名请求文件，用于CA证书给服务端证书签名。IP需要换成自己服务器的IP地址，或者域名都可以。生成文件server.csr&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl req -subj &amp;quot;/CN=192.168.3.171&amp;quot; -sha256 -new -key server-key.pem -out server.csr  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;6 配置白名单，用多个用逗号隔开，例如： IP:192.168.3.171,IP:0.0.0.0，这里需要注意，虽然0.0.0.0可以匹配任意，但是仍然需要配置你的服务器IP，如果省略会造成错误&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;echo subjectAltName = DNS:www.xxx.com,IP:192.168.3.171,IP:0.0.0.0 &amp;gt;&amp;gt; extfile.cnf &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;7 将Docker守护程序密钥的扩展使用属性设置为仅用于服务器身份验证&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;echo extendedKeyUsage = serverAuth &amp;gt;&amp;gt; extfile.cnf  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;8 创建CA证书签名好的服务端证书，期间需要输入CA证书私钥密码，生成文件为server-cert.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out server-cert.pem -extfile extfile.cnf  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;9 创建客户端私钥，生成文件为key.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl genrsa -out key.pem 4096  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;10 创建客户端证书签名请求文件，用于CA证书给客户证书签名，生成文件client.csr&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl req -subj '/CN=client' -new -key key.pem -out client.csr  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;11 要使密钥适合客户端身份验证，请创建扩展配置文件&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;echo extendedKeyUsage = clientAuth &amp;gt;&amp;gt; extfile.cnf  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;12 创建CA证书签名好的客户端证书，期间需要输入CA证书私钥密码，生成文件为cert.pem&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out cert.pem -extfile extfile.cnf  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;13 删除不需要的文件，两个证书签名请求&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;rm -v client.csr server.csr  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;14 修改证书为只读权限保证证书安全&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;chmod -v 0400 ca-key.pem key.pem server-key.pem  chmod -v 0444 ca.pem server-cert.pem cert.pem  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;15 归集服务器证书&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;cp server-*.pem  /etc/docker/ &amp;amp;&amp;amp; cp ca.pem /etc/docker/  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;最终生成文件如下，有了它们我们就可以进行基于TLS的安全访问了&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;- ca.pem CA证书 - ca-key.pem CA证书私钥 - server-cert.pem 服务端证书 - server-key.pem 服务端证书私钥 - cert.pem 客户端证书 - key.pem 客户端证书私钥  &lt;/code&gt;&lt;/pre&gt; &lt;h3&gt;一步生成&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;mkdir /docker-ca &amp;amp;&amp;amp; cd /docker-ca \ &amp;amp;&amp;amp; &amp;amp;&amp;amp;openssl genrsa -aes256 -out ca-key.pem 4096\ &amp;amp;&amp;amp;openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem\ &amp;amp;&amp;amp;openssl genrsa -out server-key.pem 4096\ &amp;amp;&amp;amp;openssl req -subj &amp;quot;/CN=xxx.com&amp;quot; -sha256 -new -key server-key.pem -out server.csr\ &amp;amp;&amp;amp;echo subjectAltName = DNS:xxx.com,IP:192.168.3.171,IP:0.0.0.0 &amp;gt;&amp;gt; extfile.cnf\ &amp;amp;&amp;amp;echo extendedKeyUsage = serverAuth &amp;gt;&amp;gt; extfile.cnf\ &amp;amp;&amp;amp;openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out server-cert.pem -extfile extfile.cnf\ &amp;amp;&amp;amp;openssl genrsa -out key.pem 4096\ &amp;amp;&amp;amp;openssl req -subj '/CN=client' -new -key key.pem -out client.csr\ &amp;amp;&amp;amp;echo extendedKeyUsage = clientAuth &amp;gt;&amp;gt; extfile.cnf\ &amp;amp;&amp;amp;openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \-CAcreateserial -out cert.pem -extfile extfile.cnf\ &amp;amp;&amp;amp;rm -v client.csr server.csr\ &amp;amp;&amp;amp;chmod -v 0400 ca-key.pem key.pem server-key.pem\ &amp;amp;&amp;amp;chmod -v 0444 ca.pem server-cert.pem cert.pem &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;第二步 配置Docker支持TLS&lt;/h1&gt; &lt;p&gt;1 修改docker.service文件&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;vi /usr/lib/systemd/system/docker.service  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;2 修改以ExecStart开头的配置，开启TLS认证，并配置好CA证书、服务端证书和服务端私钥&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;ExecStart=/usr/bin/dockerd --tlsverify --tlscacert=/etc/docker/ca.pem --tlscert=/etc/docker/server-cert.pem --tlskey=/etc/docker/server-key.pem -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;3 重新加载daemon&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;systemctl daemon-reload &amp;amp;&amp;amp; systemctl restart docker  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;4 重启docker&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;service docker restart  &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;第三步 配置idea&lt;/h1&gt; &lt;p&gt;保存相关客户端的pem文件到本地&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;ca.pem cert.pem key.pem  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;原文链接：https://blog.csdn.net/hon_vin/article/details/108058339&lt;/p&gt;</content:encoded>
      <pubDate>Thu, 27 Jun 2019 08:12:00 GMT</pubDate>
    </item>
    <item>
      <title>雪花算法生成的id太长导致js精度丢失</title>
      <link>https://gitlab.520531.xyz/article/snow-flake-generator-js-bugs</link>
      <content:encoded>&lt;p&gt;雪花算法，具体的就不介绍了，搜索引擎一大堆。雪花算法生成的一共是19位long型数字，可以保证增长趋势。 如果把数据发送到前端，前端js接收后会转number，而js的number最大长度只有16位，所以就会产生精度丢失的问题。如果我们用了雪花算法做id，那么前端根据id将查询不到数据。&lt;/p&gt; &lt;p&gt;从大的方面说，主要有两种解决方法：&lt;/p&gt; &lt;ol&gt; &lt;li&gt; &lt;p&gt;后端把long转换位string发送到前端，具体有以下几种做法 (1). 把需要转换的字段加上序列化注解，在序列化的时候就转成string&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;@JsonSerialize(using = ToStringSerializer.class) private Long id; &lt;/code&gt;&lt;/pre&gt; &lt;/li&gt; &lt;/ol&gt; &lt;p&gt;(2). 全局配置，直接修改全局的序列化器，把所有的long都转成string&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt; SimpleModule simpleModule = new SimpleModule();  //long转string  simpleModule.addSerializer(Long.class, ToStringSerializer.instance);  objectMapper.registerModule(simpleModule); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;(3). 笔者后端使用的mongo存储此次业务数据，并未建立实体pojo，这种情况可以自己处理，把long转位string&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;Document find = new Document(); find.put(&amp;quot;softwareId&amp;quot;,softwareId); Spliterator&amp;lt;Document&amp;gt; spliterator = mongoTemplate.getCollection(MongoConstant.PARAM_TEMPLATE).find(find).spliterator(); List&amp;lt;Document&amp;gt; logList = StreamSupport.stream(spliterator, false).map(doc-&amp;gt;{      doc.put(&amp;quot;_id&amp;quot;,String.valueOf(doc.get(&amp;quot;_id&amp;quot;)));      return doc; }).collect(Collectors.toList()); &lt;/code&gt;&lt;/pre&gt; &lt;ol start="2"&gt; &lt;li&gt;既然精度丢失发生在前端，也可以从前端入手，替换反序列化支持long的json反序列化工具，但是考虑到目前的主流json反序列化工具都会把数字类型反序列化成number，而使用第三方工具可能引发其他问题，本次暂不做深究，感兴趣的小伙伴可以尝试以下。&lt;/li&gt; &lt;/ol&gt;</content:encoded>
      <pubDate>Tue, 30 Apr 2019 07:29:00 GMT</pubDate>
    </item>
    <item>
      <title>三星电视进入工厂模式方法</title>
      <link>https://gitlab.520531.xyz/article/32</link>
      <content:encoded>&lt;p&gt;&lt;strong&gt;中国区&lt;/strong&gt; 信息 + 菜单 + 静音 + 电源&lt;/p&gt; &lt;p&gt;&lt;strong&gt;美国区&lt;/strong&gt; 同时按下（一定要）：信息 + 菜单 + 静音 + 电源 接下来，将以下顺序输入到遥控器中：静音 &amp;gt; 1 &amp;gt; 8 &amp;gt; 2 &amp;gt; 电源&lt;/p&gt;</content:encoded>
      <pubDate>Wed, 17 Apr 2019 08:02:00 GMT</pubDate>
    </item>
    <item>
      <title>JMeter中文乱码</title>
      <link>https://gitlab.520531.xyz/article/jmeter-chinese-decode</link>
      <content:encoded>&lt;p&gt;修改 /bin/jmeter.properties&lt;/p&gt; &lt;p&gt;默认编码是8859-1，修改 sampleresult.default.encoding 为 utf-8&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;# The encoding to be used if none is provided (default ISO-8859-1) sampleresult.default.encoding=utf-8 &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Wed, 20 Mar 2019 07:26:00 GMT</pubDate>
    </item>
    <item>
      <title>求两点中垂线上的点坐标</title>
      <link>https://gitlab.520531.xyz/article/midder-line-point-sum</link>
      <content:encoded>&lt;pre&gt;&lt;code class="language-js"&gt;function a(x0,y0,x1,y1,p){   var k = -1/((y1-y0)/(x1-x0))   var b = (y1+y0)/2 -k*((x0+x1)/2)   var x = (x1+x0)/2   if(k&amp;lt;0){  p=Math.abs(p)   }else{  p=-1*(Math.abs(p))   }   var xn = x*(1+p)   y=k*xn+b   console.log(xn+&amp;quot;,&amp;quot;+y) }  function b(){  var x0=1,y0=5,x1=12,y1=21  var step = 0.0001   for(var i=0;i&amp;lt;2;i+=step){   a(x0,y0,x1,y1,i)  } }  b() &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Mon, 11 Mar 2019 10:39:00 GMT</pubDate>
    </item>
    <item>
      <title>@Configuration注解中的proxyBeanMethods是干什么的</title>
      <link>https://gitlab.520531.xyz/article/java-spring-note-20220411</link>
      <content:encoded>&lt;p&gt;很多时候我们写configuration时候会写很多@Bean这种注解，用来向ioc容器注册实例。于是很可能出现以下这种代码&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;    @Bean     public A getA(){         System.out.println(&amp;quot;new a&amp;quot;);         return new A();     }      @Bean     public C c1(){         C c = new C();         c.setA(getA());         return c;     }      @Bean     public C c2(){         C c = new C();         c.setA(getA());         return c;     } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;默认情况下，spring会为@Configuration注解下的bean构造方法提供代理支持（用来描述bean之间的依赖关系），对getA增强过后，那么以上中c1里的a和c2里的a则都会获取同一个A的引用，如果某些情况下需要两个不同的a，则需要设置proxyBeanMethods为false。&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 06 Jan 2019 13:43:00 GMT</pubDate>
    </item>
    <item>
      <title>Caddy一键安装（可反代，tls）</title>
      <link>https://gitlab.520531.xyz/article/caddy-install-config</link>
      <content:encoded>&lt;h3&gt;&lt;strong&gt;安装&lt;/strong&gt;&lt;/h3&gt; &lt;p&gt;Github地址：&lt;a href="https://github.com/sayem314/Caddy-Web-Server-Installer" target="_blank"&gt;https://github.com/sayem314/Caddy-Web-Server-Installer&lt;/a&gt;&lt;/p&gt; &lt;p&gt;已验证系统：Ubuntu 14.x、15.x、16.x，Debian 7.x、8.x、9.x，CentOS 6.8、7.2。&lt;/p&gt; &lt;p&gt;运行以下命令：&lt;/p&gt; &lt;p&gt;安装命令：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;wget [https://git.io/vra5C](https://git.io/vra5C) -O - -o /dev/null|bash  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后使用下列命令进行操作：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;caddy start #开启Caddy Web Server   caddy stop #停止Caddy Web Server   caddy reload #重载Caddy Web Server   caddy restart #重启Caddy Web Server   caddy status #查看Caddy Web Server状态   caddy install #安装Caddy Web Server   caddy edit #编辑配置文件Caddyfile   caddy service #使Caddy Web Server成为一项服务(upstart/systemd)   caddy update #升级Caddy Web Server   caddy delete #卸载Caddy and data   caddy about #关于Caddy Web Server   caddy version #检测脚本/Caddy/PHP5-fpm版本信息  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;安装插件命令：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;caddy install http.cache,http.filemanager,http.ipfilter,http.ratelimit  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;安装caddy的时候会要求你输入域名，邮箱（帮你自动签发ssl），然后使用命令启动caddy即可！&lt;/p&gt; &lt;p&gt;虚拟主机文件夹：/var/caddywww&lt;br /&gt; 配置文件夹：/etc/Caddyfile&lt;br /&gt; 更多插件参考：&lt;a href="https://caddyserver.com/download" target="_blank"&gt;https://caddyserver.com/download&lt;/a&gt;&lt;a href="https://caddyserver.com/download。" target="_blank"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;如遇到异常，可手动执行&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;wget -q --no-check-certificate &amp;quot;https://caddyserver.com/download/linux/amd64?license=personal&amp;amp;telemetry=off&amp;quot; -O &amp;quot;caddy_linux_custom.tar.gz&amp;quot; mv caddy_linux_custom.tar.gz /opt caddy install &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Sun, 30 Sep 2018 01:54:00 GMT</pubDate>
    </item>
    <item>
      <title>feign下载文件</title>
      <link>https://gitlab.520531.xyz/article/feign-download-file</link>
      <content:encoded>&lt;h1&gt;服务提供者&lt;/h1&gt; &lt;pre&gt;&lt;code class="language-java1"&gt;@ApiOperation(&amp;quot;下载文件&amp;quot;) @GetMapping(&amp;quot;/download&amp;quot;) public void download(HttpServletRequest request, HttpServletResponse response, @RequestParam(&amp;quot;path&amp;quot;)String path) throws IOException {  request.setCharacterEncoding(&amp;quot;utf-8&amp;quot;);  File file = new File(path);  String fileName = file.getName();  ServletOutputStream outputStream = response.getOutputStream();  response.setContentType(&amp;quot;application/octet-stream&amp;quot;);  fileName = new String(fileName.getBytes(&amp;quot;UTF-8&amp;quot;),&amp;quot;ISO8859-1&amp;quot;);  response.setHeader(&amp;quot;Content-Disposition&amp;quot;, &amp;quot;attachment;filename=&amp;quot; + fileName);  byte[] buffer = new byte[1024];  int readLength;  FileInputStream fis = new FileInputStream(file);  while ((readLength=fis.read(buffer))!= -1) {   outputStream.write(buffer, 0, readLength);   outputStream.flush();  }  IoUtil.close(fis);  IoUtil.close(outputStream); } &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;服务消费者&lt;/h1&gt; &lt;p&gt;feign接口，必须返回Response&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;@GetMapping(&amp;quot;/download&amp;quot;) Response downloadFile( @RequestParam(&amp;quot;path&amp;quot;)String path) throws IOException; &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;controller&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;@ApiOperation(value = &amp;quot;下载文件&amp;quot;) @GetMapping(&amp;quot;/downloadFile&amp;quot;) public void downloadFile(HttpServletResponse response, @RequestParam(&amp;quot;path&amp;quot;)String path) throws IOException {  Response responseFromRemote = proxyFileFeign.downloadFile(path);  HttpUtil.downloadFeignFile(response, responseFromRemote); } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;工具类实现&lt;/p&gt; &lt;pre&gt;&lt;code class="language-java"&gt;/**  * feign代理下载文件工具  * @param responseFromRemote feign的response  * @date 2022/4/22  */ public static void downloadFeignFile(HttpServletResponse response, Response responseFromRemote) throws IOException {  Response.Body body = responseFromRemote.body();  /**FilterInputStream**/  InputStream inputStream = body.asInputStream();  OutputStream  outputStream = response.getOutputStream();  response.setHeader(&amp;quot;content-disposition&amp;quot;,responseFromRemote.headers().get(&amp;quot;content-disposition&amp;quot;).stream().collect(Collectors.joining(&amp;quot;;&amp;quot;)));  response.setHeader(&amp;quot;content-type&amp;quot;,responseFromRemote.headers().get(&amp;quot;content-disposition&amp;quot;).stream().collect(Collectors.joining(&amp;quot;;&amp;quot;)));  byte[] buffer = new byte[1024 * 8];  int count;  while ((count = inputStream.read(buffer)) != -1) {   outputStream.write(buffer, 0, count);   outputStream.flush();  }  IoUtil.close(inputStream);  IoUtil.close(outputStream); }  &lt;/code&gt;&lt;/pre&gt; &lt;h1&gt;读写文件需要注意的点&lt;/h1&gt; &lt;p&gt;1.文件大小未知的情况，不要一次性读取整个文件进内存，太耗内存，甚至oom&lt;/p&gt; &lt;p&gt;2.小文件如果一次性读取，inputStream.available()的返回值不是全部字节大小，根据jdk注释&lt;/p&gt; &lt;pre&gt;&lt;code&gt;Returns: an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking or 0 when it reaches the end of the input stream. &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;返回的是预估可以一次性不阻塞读取的大小。&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 25 Sep 2018 02:20:00 GMT</pubDate>
    </item>
    <item>
      <title>只有ipv6，如何访问ipv4资源</title>
      <link>https://gitlab.520531.xyz/article/dns64-nat64-ipv6</link>
      <content:encoded>&lt;p&gt;分享两个可以用的dns64+nat64节点&lt;/p&gt; &lt;p&gt;设置dns为&lt;/p&gt; &lt;p&gt;http://www.trex.fi/2011/dns64.html&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;nameserver 2001:67c:2b0::4 nameserver 2001:67c:2b0::6  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;或&lt;/p&gt; &lt;p&gt;https://go6lab.si/current-ipv6-tests/nat64dns64-public-test/&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;nameserver 2001:67c:27e4:15::6411 nameserver 2001:67c:27e4::64 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;为什么修改dns之后可以实现ipv6访问ipv4资源?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;目标dns服务器会判断我们要访问的网址有没有ipv6，如果没有ipv6，则dns服务器会通过其他具有ipv4的主机请求数据，并返回给我们，从而达到了ipv6 only机器访问ipv4资源的目的。同时需要注意的是，代请求ipv4的service会记录我们的访问记录。&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 10 Jul 2018 01:13:00 GMT</pubDate>
    </item>
    <item>
      <title>debian</title>
      <link>https://gitlab.520531.xyz/article/debian-10-learn-shell</link>
      <content:encoded>&lt;p style="margin-top: 8px; margin-bottom: 8px; padding: 0px; color: rgb(55, 55, 55); font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; line-height: 2em; font-family: &amp;quot;Open Sans&amp;quot;, sans-serif; background-color: rgb(248, 248, 248);"&gt;新安装的debian系统，用vi打开后方向键变ABCD了。&lt;br&gt;解决方法：&lt;br&gt;1.用vi打开其配置文件：&lt;/p&gt;&lt;pre class="code" style="margin-top: 10px; padding: 8px 10px 8px 12px; font-family: Menlo, Monaco, Consolas, &amp;quot;Andale Mono&amp;quot;, &amp;quot;lucida console&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace; border-left-width: 5px; border-color: rgb(221, 221, 221) rgb(221, 221, 221) rgb(221, 221, 221) rgb(108, 226, 108); border-image: none 100% / 1 / 0 stretch; background: none 0% 0% repeat scroll rgb(241, 241, 241); font-size: 12px;"&gt;&lt;code class="bash"&gt;vi /etc/vim/vimrc.tiny &lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-top: 8px; margin-bottom: 8px; padding: 0px; color: rgb(55, 55, 55); font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; line-height: 2em; font-family: &amp;quot;Open Sans&amp;quot;, sans-serif; background-color: rgb(248, 248, 248);"&gt;2.将如下语句写入vi配置文件：&lt;/p&gt;&lt;pre class="code" style="margin-top: 10px; padding: 8px 10px 8px 12px; font-family: Menlo, Monaco, Consolas, &amp;quot;Andale Mono&amp;quot;, &amp;quot;lucida console&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace; border-left-width: 5px; border-color: rgb(221, 221, 221) rgb(221, 221, 221) rgb(221, 221, 221) rgb(108, 226, 108); border-image: none 100% / 1 / 0 stretch; background: none 0% 0% repeat scroll rgb(241, 241, 241); font-size: 12px;"&gt;&lt;code class="bash"&gt;set nocompatible          //找到set compatible改为set nocompatible  &lt;/code&gt;&lt;/pre&gt;&lt;p style="margin-top: 8px; margin-bottom: 8px; padding: 0px; color: rgb(55, 55, 55); font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; line-height: 2em; font-family: &amp;quot;Open Sans&amp;quot;, sans-serif; background-color: rgb(248, 248, 248);"&gt;设置完后保存退出就可以正常使用了。&lt;/p&gt;&lt;p style="margin-top: 8px; margin-bottom: 8px; padding: 0px; color: rgb(55, 55, 55); font-variant-numeric: normal; font-variant-east-asian: normal; font-stretch: normal; line-height: 2em; font-family: &amp;quot;Open Sans&amp;quot;, sans-serif; background-color: rgb(248, 248, 248);"&gt;如果退格键不能使用，可以在刚才的下面再加一句：&lt;/p&gt;&lt;pre class="code" style="margin-top: 10px; padding: 8px 10px 8px 12px; font-family: Menlo, Monaco, Consolas, &amp;quot;Andale Mono&amp;quot;, &amp;quot;lucida console&amp;quot;, &amp;quot;Courier New&amp;quot;, monospace; border-left-width: 5px; border-color: rgb(221, 221, 221) rgb(221, 221, 221) rgb(221, 221, 221) rgb(108, 226, 108); border-image: none 100% / 1 / 0 stretch; background: none 0% 0% repeat scroll rgb(241, 241, 241); font-size: 12px;"&gt;&lt;code class="bash"&gt;set backspace=2&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;1. 安装ssh服务&lt;/p&gt;&lt;p&gt;sudo apt-get update #更新软件源&lt;/p&gt;&lt;p&gt;sudo apt-get install ssh #安装&lt;/p&gt;&lt;p&gt;2.修改sshd_config文件，命令为：vi /etc/ssh/sshd_config&lt;/p&gt;&lt;p&gt;将#PasswordAuthentication no的注释去掉，并且将no修改为yes&lt;/p&gt;&lt;p&gt;将#PermitRootLogin prohibit-password的注释去掉，将prohibit-password改为yes&lt;/p&gt;&lt;p&gt;PasswordAuthentication yes&lt;/p&gt;&lt;p&gt;PermitRootLogin yes&lt;/p&gt;&lt;p&gt;或echo -e “PasswordAuthentication yes\nPermitRootLogin yes” &amp;gt;&amp;gt; /etc/ssh/sshd_config&lt;/p&gt;&lt;p&gt;3.启动SSH服务，命令为：/etc/init.d/ssh start // 或者service ssh start&lt;/p&gt;&lt;p&gt;4.验证SSH服务状态，命令为：/etc/init.d/ssh status&lt;/p&gt;&lt;p&gt;添加开机自启动 systemctl enable ssh&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;腾讯云轻量&lt;/p&gt;&lt;p&gt;安装curl提示已安装解决方案&lt;/p&gt;&lt;p&gt;备份 cp /var/lib/dpkg/status /var/lib/dpkg/status.bac&lt;/p&gt;&lt;p&gt;找到/var/lib/dpkg/status curl对应的package 删除后，即可安装curl&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 26 Jan 2018 02:50:00 GMT</pubDate>
    </item>
    <item>
      <title>docker配置</title>
      <link>https://gitlab.520531.xyz/article/docker-setting-remote-access</link>
      <content:encoded>&lt;p&gt;修改docker.service vim/usr/lib/systemd/system/docker.service 在[Service]部分，修改ExecStart参数，在最后增加-Htcp://0.0.0.0:2375，监听所有网络接口上的2375端口。&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;ExecStart=/usr/bin/dockerd-Hfd://--containerd=/run/containerd/containerd.sock-Htcp://0.0.0.0:2375  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;然后重新加载&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;systemctl daemon-reload systemctl restart docker  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;搜索命令&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker search xxxx  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;拉取&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker pull xxxx &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;后台启动&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker run --name 自定义名称 -d -p 8080:8080 xxxx &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;自启动&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker container update --restart=always 容器名字 &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;列出所有容器&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker container  ls  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;查询container&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;dokcer ps（正在运行的） / docker ps -a（全部的）  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;进入容器&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;docker exec -it 容器ID/名称 /bin/bash  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;退出容器&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;exit  或者 ctrl + p + q （后台运行） &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Thu, 23 Nov 2017 12:51:00 GMT</pubDate>
    </item>
    <item>
      <title>站在风口浪尖上</title>
      <link>https://gitlab.520531.xyz/article/economic-internal-circulation-2020</link>
      <content:encoded>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;我们这代人，又来到了时代的风口浪尖。上一次巨大的风口应该就是1978年改革开放，奠定了中国经济四十多年的高速发展！当前的新冠疫情未退，全球化进程正在消退，起码对中国来说是正在消退的。尤其是不停鼓吹的经济内循环，这是不是标志着改革开放正在衰退。终于，我们这代人，站在了时代的风口浪尖，以往的经济推动力，也会面临巨大挑战。走向没落的，也许是楼市。&lt;/p&gt; &lt;p&gt;  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;在过去的十几年间，楼市一路高歌猛进，房价不仅绑架了普通老百姓，也同样造就了土地财政。在次期间，60，70，80年代的这波人，也是享受这波房地产经济红利最大的人群，个人财富得到了快速的积累。与此同时，90后00后，走出社会的一瞬间，就要面对六个钱包被掏空买房的状况，这无疑是悲哀的，走向工作岗位的那一刻，就在负债。也许90，00年代出生的我们，困难远远不止于此。&lt;/p&gt; &lt;p&gt;  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;中国是个出口大国，全球化的消退，也同时意味着就业形势的严峻。从事于外贸出口相关的上下游产业，相关服务业从业总数，这个数字肯定也是大的惊人，而90末期，00初期出生的这群人，毕业对于很多人也许就是以为着失业。当他们成为这个社会发展中流砥柱的时候，也许在财富上的积累会比上几代人困难很多。这代人应该怎么才能摆脱现实的困境，在时代变化中投机？&lt;/p&gt; &lt;p&gt;  &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;现在才开始买房也许对于90，00这代人获得快速的财富积累也许已经迟了，那么股市会否给年轻人一些机会呢？答案当然是不容乐观，从2015年股灾开始，中国的股市几乎和全球股市背道而驰，这是一个不正常的现象。经过了5年调整，筑底，也许股市的底正在成熟。但是股市毕竟反映的是企业盈利能力，以及发展前景，从这两项整体看来，想要股市形成大牛市，在其中大赚一笔，也许还不如去澳门博一把赢的几率大。&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 03 Nov 2017 09:16:00 GMT</pubDate>
    </item>
    <item>
      <title>关于信仰的一点随记</title>
      <link>https://gitlab.520531.xyz/article/about-faith-thinking</link>
      <content:encoded>&lt;p style="margin:0cm;margin-bottom:.0001pt"&gt;随着年龄经历的增长，不止问过自己，我到底有没有信仰？好像我从小所受的教育都是无神论，我们没有&lt;span lang="EN-US"&gt;Jesus&lt;/span&gt;，没有喇嘛，班禅。是的，无神论者怎么会有信仰。&lt;span lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 11.25pt 0cm 0.0001pt;"&gt;今天&lt;span lang="EN-US"&gt;,&lt;/span&gt;身边无不充斥着无道德，无下限的行为。看下快手，抖音，各种网站，无不是衣着暴露，&lt;span lang="EN-US"&gt;sexy&lt;/span&gt;的女性图片，其中不乏很多大学生，甚至未成年，各种贿赂，权色交易。是不是每个人都思考过这个问题，&lt;span lang="EN-US"&gt;What's Going on&lt;/span&gt;？这个世界究竟怎么了。忽然想起以前听到过的一句话，因为今天的中国人没有信仰，大家只能信仰钱，突破道德底线也就理所当然。&lt;span lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 11.25pt 0cm 0.0001pt;"&gt;是的，因为没有信仰，所以只能抓紧钱。这样的话，似乎各种现象就好理解了，因为心中没有信仰，无所畏惧，干出什么特别事情也是可能的。中国有句老话，叫做&lt;span lang="EN-US"&gt;“&lt;/span&gt;善有善报，恶有恶报&lt;span lang="EN-US"&gt;”&lt;/span&gt;，当下的我们是否还相信善恶终有报呢，对于这个社会主流氛围来说，答案是否定的。如果那些人有信仰，相信红黄蓝幼儿园就不会出事，也不会有毒疫苗，毒奶粉的事情。&lt;span lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 11.25pt 0cm 0.0001pt;"&gt;希望大家都成为一个有信仰的人，是信仰而不是疑神疑鬼。当愉悦的时候，心存感激。当遇到挫折，绝望的时候，心存希望。做坏事的时候，心存畏惧。&lt;span lang="EN-US"&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p style="margin: 11.25pt 0cm 0.0001pt;"&gt;也许这个世界上并没有上帝，但是只要我们心中有，无论我们的神是，耶稣上帝，穆罕穆德，如来佛祖，还是班禅喇嘛&lt;span lang="EN-US"&gt;...&lt;/span&gt;在做任何事情的时候，于我们来说都是一种约束力。&lt;/p&gt;&lt;p style="margin: 11.25pt 0cm 0.0001pt;"&gt;&lt;br&gt;&lt;/p&gt; &lt;iframe style="width:640px;height:360px;" src="//player.bilibili.com/player.html?aid=840508229&amp;amp;bvid=BV1P54y1X7US&amp;amp;cid=186481661&amp;amp;page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"&gt; &lt;/iframe&gt;</content:encoded>
      <pubDate>Thu, 14 Sep 2017 11:51:00 GMT</pubDate>
    </item>
    <item>
      <title>解锁网易云音乐之二（ios解锁）</title>
      <link>https://gitlab.520531.xyz/article/Unblock-Netease-Music-Ios</link>
      <content:encoded>&lt;p&gt;上一篇写了如何搭建解锁服务，本篇着重具体配置，因为ios客户端的特殊性，直接搭建的服务器并不能在ios正常使用，需要搭建一个https转发服务器，本篇使用caddy搭建，nginx可自行百度，原理相同，添加如下配置：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;youdomain.com {     tls xxxxxxxxx@gmail.com     gzip  timeouts none     header / Strict-Transport-Security &amp;quot;max-age=31536000;&amp;quot;     proxy / http://localhost:8080{     } } &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;服务器端启动方式变为以下：&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;#对ios解锁 nohup /usr/bin/node /root/UnblockNeteaseMusic/app.js -s -p 8080 -e https://youdomain.com &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; #对windows解锁 nohup /usr/bin/node /root/UnblockNeteaseMusic/app.js -s -p 8081 -e http://music.163.com &amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp; &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;对于ios中的小火箭则添加http代理，并且加入以下规则（推荐国外服务器使用）&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt; DOMAIN-SUFFIX,music.126.net,DIRECT DOMAIN-SUFFIX,music.163.com,NeteaseUnlocker DOMAIN-SUFFIX,api.iplay.163.com,NeteaseUnlocker DOMAIN-SUFFIX,mam.netease.com,NeteaseUnlocker DOMAIN-SUFFIX,hz.netease.com,NeteaseUnlocker &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;以上规则也可简化为（推荐国内服务器使用）&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;DOMAIN-SUFFIX,music.126.net,DIRECT  USER-AGENT,NeteaseMusic*,NeteaseUnlocker  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;至此，ios设备就解锁完成，尽情的享受无限制的音乐吧！&lt;/p&gt;</content:encoded>
      <pubDate>Sun, 20 Aug 2017 09:03:00 GMT</pubDate>
    </item>
    <item>
      <title>linux文件搜索命令</title>
      <link>https://gitlab.520531.xyz/article/linux-file-search</link>
      <content:encoded>&lt;h3 id="-span-style-outline-style-initial-outline-width-0px-margin-0px-padding-0px-font-family-quot-microsoft-yahei-quot-quot-sf-pro-display-quot-roboto-noto-arial-quot-pingfang-sc-quot-sans-serif-overflow-wrap-break-word-font-size-24px-1-find-span-"&gt;&lt;span style="outline-style: initial; outline-width: 0px; margin: 0px; padding: 0px; font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;SF Pro Display&amp;quot;, Roboto, Noto, Arial, &amp;quot;PingFang SC&amp;quot;, sans-serif; overflow-wrap: break-word; font-size: 24px;"&gt;1.find命令&lt;/span&gt;&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;        1.按照文件名查找 &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;　　　　(1)find / -name httpd.conf　　#在根目录下查找文件httpd.conf，表示在整个硬盘查找&lt;/p&gt; &lt;p&gt;　　　　(2)find /etc -name httpd.conf　　#在/etc目录下文件httpd.conf&lt;/p&gt; &lt;p&gt;　　　　(3)find /etc -name '&lt;em&gt;srm&lt;/em&gt;'　　#使用通配符*(0或者任意多个)。表示在/etc目录下查找文件名中含有字符串‘srm’的文件&lt;/p&gt; &lt;p&gt;　　　　(4)find . -name 'srm*' 　　#表示当前目录下查找文件名开头是字符串‘srm’的文件&lt;/p&gt; &lt;p&gt;　　　　2.按照文件特征查找 　　　　&lt;/p&gt; &lt;p&gt;　　　　(1)find / -amin -10 　　# 查找在系统中最后10分钟访问的文件(access time)&lt;/p&gt; &lt;p&gt;　　　　(2)find / -atime -2　　 # 查找在系统中最后48小时访问的文件&lt;/p&gt; &lt;p&gt;　　　　(3)find / -empty 　　# 查找在系统中为空的文件或者文件夹&lt;/p&gt; &lt;p&gt;　　　　(4)find / -group cat 　　# 查找在系统中属于 group为cat的文件&lt;/p&gt; &lt;p&gt;　　　　(5)find / -mmin -5 　　# 查找在系统中最后5分钟里修改过的文件(modify time)&lt;/p&gt; &lt;p&gt;　　　　(6)find / -mtime -1 　　#查找在系统中最后24小时里修改过的文件&lt;/p&gt; &lt;p&gt;　　　　(7)find / -user fred 　　#查找在系统中属于fred这个用户的文件&lt;/p&gt; &lt;p&gt;　　　　(8)find / -size +10000c　　#查找出大于10000000字节的文件(c:字节，w:双字，k:KB，M:MB，G:GB)&lt;/p&gt; &lt;p&gt;　　　　(9)find / -size -1000k 　　#查找出小于1000KB的文件&lt;/p&gt; &lt;p&gt;　　　　3.使用混合查找方式查找文件&lt;/p&gt; &lt;p&gt;　　　　参数有： ！，-and(-a)，-or(-o)。&lt;/p&gt; &lt;p&gt;　　　　(1)find /tmp -size +10000c -and -mtime +2 　　#在/tmp目录下查找大于10000字节并在最后2分钟内修改的文件&lt;/p&gt; &lt;p&gt;　　 (2)find / -user fred -or -user george 　　#在/目录下查找用户是fred或者george的文件文件&lt;/p&gt; &lt;p&gt;　　 (3)find /tmp ! -user panda　　#在/tmp目录中查找所有不属于panda用户的文件&lt;/p&gt; &lt;h3 id="-span-style-outline-style-initial-outline-width-0px-margin-0px-padding-0px-font-family-quot-microsoft-yahei-quot-quot-sf-pro-display-quot-roboto-noto-arial-quot-pingfang-sc-quot-sans-serif-overflow-wrap-break-word-font-size-24px-2-witch-span-"&gt;&lt;span style="outline-style: initial; outline-width: 0px; margin: 0px; padding: 0px; font-family: &amp;quot;Microsoft YaHei&amp;quot;, &amp;quot;SF Pro Display&amp;quot;, Roboto, Noto, Arial, &amp;quot;PingFang SC&amp;quot;, sans-serif; overflow-wrap: break-word; font-size: 24px;"&gt;2.witch命令&lt;/span&gt;&lt;/h3&gt; &lt;pre&gt;&lt;code&gt;        &amp;lt;span style="color: rgb(79, 79, 79); font-family: &amp;amp;quot;Microsoft YaHei&amp;amp;quot;, &amp;amp;quot;SF Pro Display&amp;amp;quot;, Roboto, Noto, Arial, &amp;amp;quot;PingFang SC&amp;amp;quot;, sans-serif; font-size: 18px; text-align: justify;"&amp;gt;which命令的作用是，在PATH变量指定的路径中，搜索某个系统命令的位置，并且返回第一个搜索结果。&amp;lt;/span&amp;gt;&amp;lt;span style="outline-style: initial; outline-width: 0px; margin: 0px; padding: 0px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; overflow-wrap: break-word; font-size: 18px; text-align: justify; color: rgb(75, 75, 75);"&amp;gt;在找到第一个符合条件的程序文件时，就立刻停止搜索，省略其余未搜索目录。&amp;lt;/span&amp;gt;&amp;lt;span style="color: rgb(79, 79, 79); font-family: &amp;amp;quot;Microsoft YaHei&amp;amp;quot;, &amp;amp;quot;SF Pro Display&amp;amp;quot;, Roboto, Noto, Arial, &amp;amp;quot;PingFang SC&amp;amp;quot;, sans-serif; font-size: 18px; text-align: justify;"&amp;gt;也就是说，使用which命令，就可以看到某个系统命令是否存在，以及执行的到底是哪一个位置的命令。&amp;lt;/span&amp;gt;   &lt;/code&gt;&lt;/pre&gt;&lt;p&gt;原文链接：&lt;a href="https://blog.csdn.net/qq_37506868/article/details/79238300"&gt;https://blog.csdn.net/qq_37506868/article/details/79238300&lt;/a&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Mon, 07 Aug 2017 13:39:00 GMT</pubDate>
    </item>
    <item>
      <title>谷歌拼音输入法下载地址</title>
      <link>https://gitlab.520531.xyz/article/google-pinyin-input</link>
      <content:encoded>&lt;p style="box-sizing: inherit; outline-style: initial; outline-width: 0px; padding: 0px;"&gt;谷歌拼音输入法下载地址1：&lt;a href="http://dl.google.com/pinyin/v2/GooglePinyinInstaller_x64.exe" style="background-color: rgb(255, 255, 255);"&gt;http://dl.google.com/pinyin/&lt;/a&gt;&lt;span style="box-sizing: inherit; outline-style: initial;"&gt;&lt;a href="http://dl.google.com/pinyin/v2/GooglePinyinInstaller_x64.exe"&gt;v2&lt;/a&gt;&lt;/span&gt;&lt;a href="http://dl.google.com/pinyin/v2/GooglePinyinInstaller_x64.exe" style="background-color: rgb(255, 255, 255);"&gt;/GooglePinyinInstaller_x64.exe&lt;/a&gt;&lt;/p&gt;&lt;p style="box-sizing: inherit; outline-style: initial; outline-width: 0px; padding: 0px; margin-top: 0px;"&gt;&lt;span style="box-sizing: inherit; outline-style: initial; outline-width: 0px;"&gt;谷歌拼音输入法下载地址2：&lt;/span&gt;&lt;span style="box-sizing: inherit; outline-style: initial; outline-width: 0px; cursor: pointer;"&gt;&lt;a href="https://dl.google.com/pinyin/v2/GooglePinyinInstaller.exe" target="_blank"&gt;https://dl.google.com/pinyin/&lt;/a&gt;&lt;span style="box-sizing: inherit; outline-style: initial;"&gt;&lt;a href="https://dl.google.com/pinyin/v2/GooglePinyinInstaller.exe" target="_blank"&gt;v2&lt;/a&gt;&lt;/span&gt;&lt;a href="https://dl.google.com/pinyin/v2/GooglePinyinInstaller.exe" target="_blank"&gt;/GooglePinyinInstaller.exe&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 01 Aug 2017 07:53:00 GMT</pubDate>
    </item>
    <item>
      <title>解锁网易云音乐之一（搭建）</title>
      <link>https://gitlab.520531.xyz/article/Unblock-Netease-Music</link>
      <content:encoded>&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;UnblockNeteaseMusic是一款可以让网易云曲库里的灰色歌曲能够正常播放的神器。&lt;br&gt;项目地址：&lt;span class="external-link"&gt;&lt;a href="https://github.com/nondanee/UnblockNeteaseMusic" target="_blank" style="color: rgb(88, 102, 110); cursor: pointer; word-break: break-all; border-bottom: 1px solid rgb(153, 153, 153); overflow-wrap: break-word;"&gt;https://github.com/nondanee/UnblockNeteaseMusic&lt;svg xmlns="http://www.w3.org/2000/svg" width="16px" height="16px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-external-link"&gt;&lt;path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"&gt;&lt;/path&gt;&lt;polyline points="15 3 21 3 21 9"&gt;&lt;/polyline&gt;&lt;line x1="10" y1="14" x2="21" y2="3"&gt;&lt;/line&gt;&lt;/svg&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-top: 0px; margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;span style="font-weight: 700;"&gt;特性：&lt;/span&gt;&lt;/p&gt;&lt;ul style="margin: 1.5em 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;li&gt;使用 QQ / 虾米 / 百度 / 酷狗 / 酷我 / 咪咕 / JOOX 音源替换变灰歌曲链接 (默认仅启用一、五、六)&lt;/li&gt;&lt;li&gt;为请求增加&amp;nbsp;&lt;code style="font-size: 12.6px;"&gt;X-Real-IP&lt;/code&gt;&amp;nbsp;参数解锁海外限制，支持指定网易云服务器 IP，支持设置上游&amp;nbsp;&lt;code style="font-size: 12.6px;"&gt;HTTP / HTTPS&lt;/code&gt;&amp;nbsp;代理&lt;/li&gt;&lt;li&gt;完整的流量代理功能 (&lt;code style="font-size: 12.6px;"&gt;HTTP / HTTPS&lt;/code&gt;)，可直接作为系统代理 (同时支持 PAC)&lt;/li&gt;&lt;/ul&gt;&lt;div name="准备工作" data-unique="准备工作" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h2 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 1.55em; position: relative;"&gt;准备工作&lt;/h2&gt;&lt;ol style="margin: 1.5em 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;li&gt;一台VPS&lt;/li&gt;&lt;li&gt;几分钟时间&lt;/li&gt;&lt;li&gt;一个想用网易云的你&lt;/li&gt;&lt;/ol&gt;&lt;div name="正式开始安装" data-unique="正式开始安装" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h2 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 1.55em; position: relative;"&gt;正式开始安装&lt;/h2&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;测试时的系统环境：CentOS 7 其它系统差别不大&lt;/p&gt;&lt;div name="安装Nodejs" data-unique="安装Nodejs" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;安装Nodejs&lt;/h3&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;span style="font-weight: 700;"&gt;CentOS系统&lt;/span&gt;&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-bash" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" hljs language-bash" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); display: block; overflow-x: auto; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; max-height: 500px;"&gt;&lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;curl&lt;/span&gt; -sL https://rpm.nodesource.com/setup_10.x &lt;span class="token operator" style="color: rgb(103, 205, 204);"&gt;|&lt;/span&gt; &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;bash&lt;/span&gt; -  yum -y &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;install&lt;/span&gt; nodejs &lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Bash&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;span style="font-weight: 700;"&gt;Debian/Ubuntu系统&lt;/span&gt;&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-bash" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" hljs language-bash" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); display: block; overflow-x: auto; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; max-height: 500px;"&gt;&lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;curl&lt;/span&gt; -sL https://deb.nodesource.com/setup_10.x &lt;span class="token operator" style="color: rgb(103, 205, 204);"&gt;|&lt;/span&gt; &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;bash&lt;/span&gt; - apt &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;install&lt;/span&gt; -y nodejs &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;git&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Bash&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;使用&lt;code style="font-size: 12.6px;"&gt;node -v&lt;/code&gt;命令查看是否安装成功。&lt;/p&gt;&lt;div name="安装Supervisor" data-unique="安装Supervisor" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;安装Supervisor&lt;/h3&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;span style="font-weight: 700;"&gt;CentOS系统&lt;/span&gt;&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-bash" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" hljs language-bash" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); display: block; overflow-x: auto; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; max-height: 500px;"&gt;yum -y &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;install&lt;/span&gt; epel-release yum -y &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;install&lt;/span&gt; supervisor&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Bash&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;span style="font-weight: 700;"&gt;Debian/Ubuntu系统&lt;/span&gt;&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-bash" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" hljs language-bash" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); display: block; overflow-x: auto; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; max-height: 500px;"&gt;&lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;apt-get&lt;/span&gt; &lt;span class="token function" style="color: rgb(240, 141, 73);"&gt;install&lt;/span&gt; supervisor&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Bash&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div name="拉取文件" data-unique="拉取文件" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;拉取文件&lt;/h3&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;[没有git的话可以执行此命令&lt;code style="font-size: 12.6px;"&gt;yum install git&lt;/code&gt;安装]&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-git" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" language-git" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; display: block; overflow-x: auto; max-height: 500px;"&gt;git clone https://github.com/nondanee/UnblockNeteaseMusic.git cd UnblockNeteaseMusic&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Git&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div name="配置supervisor并在后台运行" data-unique="配置supervisor并在后台运行" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;配置supervisor并在后台运行&lt;/h3&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;[没有nano编辑器的话可以执行此命令&lt;code style="font-size: 12.6px;"&gt;yum -y install nano&lt;/code&gt;安装]&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-nano" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" language-nano" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; display: block; overflow-x: auto; max-height: 500px;"&gt;nano /etc/supervisord.d/netease.ini&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Nano&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt;&amp;nbsp;复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;写入以下配置：&lt;/p&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-supervisord" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" language-supervisord" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; display: block; overflow-x: auto; max-height: 500px;"&gt;[supervisord] nodaemon=false &lt;p&gt;[program:netease] user=root directory=/root/UnblockNeteaseMusic command=/usr/bin/node app.js -p 8848 autostart=true autorestart=true&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Supervisord&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt; 复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;我选择的端口号是8848，这个数值可以自定义&lt;br&gt;Tip:按下Ctrl+X然后按Y即可退出编辑界面。&lt;/p&gt;&lt;div name="启动项目" data-unique="启动项目" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;启动项目&lt;/h3&gt;&lt;div class="code-toolbar" style="border-radius: 4px; position: relative; box-shadow: rgba(0, 0, 0, 0.4) 0px 0px 20px 5px; padding-top: 30px; background-color: rgb(22, 22, 22); margin: 20px 0px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;pre class=" language-supervisord" style="overflow: hidden; font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding: 0px; margin-top: 1.5em; margin-bottom: 1.5em; line-height: 2; color: rgb(255, 255, 255); background-color: rgb(63, 63, 63); border-width: initial; border-style: none; border-color: rgb(222, 229, 231); border-radius: 0px; text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; position: relative;"&gt;&lt;code class=" language-supervisord" style="font-family: Consolas, Monaco, &amp;quot;andale mono&amp;quot;, &amp;quot;ubuntu mono&amp;quot;, monospace; padding-left: 3.5em; color: rgb(248, 248, 242); background-image: initial; background-color: rgb(49, 50, 56); text-shadow: rgba(0, 0, 0, 0.3) 0px 1px; line-height: 2; position: relative; display: block; overflow-x: auto; max-height: 500px;"&gt;systemctl start supervisord systemctl enable supervisord&lt;/code&gt;&lt;/pre&gt;&lt;div class="shelter" style="width: 6.5px; height: 6.5px; z-index: 100; background: rgb(49, 50, 56); position: absolute; bottom: 0px; right: 0px;"&gt;&lt;/div&gt;&lt;div class="toolbar" style="padding-right: 0.4em; position: absolute; top: 0.09em; right: 0.2em; width: 740px; text-align: center;"&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;span style="font-family: ubuntu, sans-serif; font-weight: 700; font-size: 0.9em; opacity: 0; color: rgb(255, 255, 255);"&gt;Supervisord&lt;/span&gt;&lt;/div&gt;&lt;div class="toolbar-item" style="padding: 0px 1px 1px 3px; display: inline-block;"&gt;&lt;button style="font-size: 12px; line-height: 12px; color: rgb(255, 255, 255); overflow: scroll hidden; transition: all 0.3s ease 0s; position: absolute; right: 6px; top: 4px; padding: 3px 5px; border-width: 1px; border-style: solid; border-color: initial; border-radius: 6px; opacity: 0; max-width: 100%;"&gt;&lt;span class="fontello fontello-tags" id="btn-copy-code" style="display: inline-block; font-size: inherit; text-rendering: auto; -webkit-font-smoothing: antialiased;"&gt; 复制&lt;/span&gt;&lt;/button&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;至此已搭建完成。可以使用了。&lt;/p&gt;&lt;p style="margin-top: 0px; margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/p&gt;&lt;div class="tip inlineBlock warning" style="background: rgb(252, 242, 233); padding: 8px 20px; border-left: 3px solid rgb(255, 120, 0); border-radius: 0px 5px 5px 0px; margin-bottom: 10px; display: inline-block; width: 740px; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;注意：如果一切顺利，但仍然无法访问代理服务器，请检查VPS的安全组或防火墙设置，放行你的UnblockNeteaseMusic服务端口&lt;/div&gt;&lt;div name="Windows客户端" data-unique="Windows客户端" style="color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;&lt;/div&gt;&lt;h3 style="font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace; font-weight: 700; line-height: 1.4; color: rgb(102, 102, 102); margin-top: 30px; font-size: 20px;"&gt;Windows客户端&lt;/h3&gt;&lt;p style="margin-bottom: 20px; word-break: break-all; color: rgb(88, 102, 110); font-family: &amp;quot;Source Sans Pro&amp;quot;, &amp;quot;Hiragino Sans GB&amp;quot;, &amp;quot;Microsoft Yahei&amp;quot;, SimSun, Helvetica, Arial, sans-serif, monospace;"&gt;打开网易云音乐客户端，点击&lt;code style="font-size: 12.6px;"&gt;设置&lt;/code&gt; - &lt;code style="font-size: 12.6px;"&gt;工具&lt;/code&gt; - &lt;code style="font-size: 12.6px;"&gt;使用自定义代理&lt;/code&gt;，选择HTTP代理。&lt;br&gt;填写服务器地址和端口。点击确定，然后重启客户端即可看到效果。&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 09 May 2017 03:03:00 GMT</pubDate>
    </item>
    <item>
      <title>毒疫苗下的恐惧</title>
      <link>https://gitlab.520531.xyz/article/du-yi-miao-page</link>
      <content:encoded>&lt;p&gt;我的一位留学韩国的朋友曾跟我说过这样一件事，在2008年中国查出了毒奶粉事件之后，很快新闻就在韩国被报道了，当时我朋友的韩国同学对她说：“恭喜你们，在弄死自己的路上又进了一步。”&lt;/p&gt; &lt;p&gt;这句话，让我朋友心寒，她无法反驳。&lt;/p&gt; &lt;p&gt;如今，我们好像又应了韩国人的那句话。这就是“毒疫苗”。&lt;/p&gt; &lt;p&gt;近日，国家药品监督管理局公告称，国家药品监督管理局通过飞行检查发现长春长生生物生产的狂犬病疫苗生产存在记录造假等严重违反《药品生产质量管理规范》行为，责令长生生物停止生产。&lt;/p&gt; &lt;p&gt;这家“长生生物”除了这次的狂犬疫苗以外，2017年还被发现有25万支“百白破”疫苗（用于预防百日咳、白喉、破伤风三种疾病）检验不合格，而这25万支疫苗几乎已经全部销售到山东，库存中仅剩186支。&lt;/p&gt; &lt;p&gt;现在我只能说，由于我们还处在发展阶段，有很多制度还不够完善，我相信，未来会越来越好的。为了早日解决这些问题，下面我要列举一些发达国家对疫苗的管控方式，看看别人是怎么做的，好的地方，我们借鉴，不好的地方，我们摒弃，希望祖国越来越好。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;英国：生产审批只有7家生产商&lt;/strong&gt; &lt;/p&gt; &lt;p&gt;疫苗的审批、生产是疫苗安全链条的第一环，也是至关重要的一环。对此，英国政府予以高度重视。&lt;br&gt;  &lt;br&gt;英国严格控制疫苗生厂商资质。在英国药品行业协会登记的成员有64家，而其中仅7家获得了英国卫生部的疫苗生厂商资质。数量之少，原因有二：第一，英国卫生部设有专门的疫苗资质审查、管理机构。要取得生产资质，必须通过严格考核，如研制能力、生产设备、资金等。第二，英国提供全民免费医疗服务，英国卫生部是欧洲最大的疫苗采购方，每年用于采购疫苗的资金超过2亿英镑，英国民众所需的全部疫苗都由英国卫生部统一采购。&lt;/p&gt; &lt;p&gt;由于英国卫生部是唯一的买家，垄断的购买力使其在与疫苗生产商的谈判中具有很大发言权，其签订的合同价远低于生产商公布的市场价。因此，英国上市的疫苗品种越来越多，而疫苗生产商的数量却越来越少。英国卫生部强大的定价能力让疫苗生产利润趋薄，使得许多企业退出该领域。 &lt;/p&gt; &lt;p&gt;&lt;strong&gt;日本：赔偿机制，申请就能获赔&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;日本在各地都设有保健所，一旦接种疫苗者出现副作用，可以向最近的保健所提出申告，并依法获得经济补偿等。这就是日本的国家赔偿机制。&lt;br&gt;  &lt;br&gt;日本法律规定，接种疫苗后如果出现后遗症导致住院，可申请医疗费外加一定补助；如果出现身体残障甚是死亡等严重情况，可申请获得遗属年金或一次性补偿及丧葬费等，金额不菲。&lt;/p&gt; &lt;p&gt;上述两项制度操作起来非常简单，只要本人提出申请，即可获得厚生大臣的直接审议，数日内可接到是否能获赔的通知。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;美国：立法保护“无过错”赔偿&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;美国有一个国家疫苗伤害赔偿项目（NVICP），赔偿由于接种疫苗而引起的伤害的个人，这种赔偿是基于“无过错”原则的。&lt;/p&gt; &lt;p&gt;所谓无过错意思是说提出索赔的人无需证明自己的伤害是由于医疗机构或疫苗生产商的过失所引起的。NVICP覆盖所有针对儿童的常规推荐疫苗，赔偿方案根据疫苗伤害表，该表总结了疫苗引起的不良反应。该表是医学专家组根据医学文献讨论确定的。美国根据这个列表建立起了疫苗救济基金。基金来源于列入疫苗伤害表中的疫苗收缴的税金。&lt;/p&gt; &lt;p&gt;我国不少儿童在接种疫苗后，产生了各种各样的不良反应，有的导致终生严重残疾，这些儿童的家庭理应得到赔偿，美国的NVICP国家赔偿机制以及“无过错”原则对于我国以后制定相关法律，相信会很有借鉴意义。美国的NVICP已经实施近30年，而我国这方面还几乎是空白。  &lt;/p&gt; &lt;p&gt;&lt;strong&gt;加拿大：疫苗全部能追回&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;一旦疫苗出现质量问题，首先要做的就是召回。对此，加拿大独有的“全国联网医疗数据库”发挥了强大的作用，不仅能做到准确、迅速，而且一支也不会少。&lt;/p&gt; &lt;p&gt;加拿大“全国联网医疗数据库”记录有三部分内容：住院病人、门诊病人和购买处方药病人的全部信息。由于每个加拿大人（也包括非公民的永久性居民）都有独一无二的医疗卡号，因此任何一项医疗记录都能清晰找到时间、地点和责任人，无法涂改、删除，包括你在何时、何地接种了何种疫苗，都可以查得一清二楚。&lt;/p&gt; &lt;p&gt;&lt;strong&gt;德国：储存运输如同运送生化武器&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;疫苗生产出来之后，就进入了储存运输这一环节。为保证疫苗的安全，德国动用了类似于运输“生化武器”的装备——“疫苗冷链”。&lt;br&gt;  &lt;br&gt;疫苗冷链是指，为保证疫苗从生产企业到接种单位运转过程中的质量而装备的储存、运输冷藏设施、设备。德国的疫苗专用运输车除驾驶室外，全部采用避光、密封性能好的特殊材料制成，每辆车都有防热、防静电、防辐射等功能。同时，每车还配有两名带武器的安保人员，其安全级别可以与运送“生化核武”的军车相比。&lt;/p&gt; &lt;p&gt;据统计，中国每年疫苗预防接种达10亿剂次。这是个惊人的数字，按照官方公布的疫苗不良反应概率是百万分之一到二，从大数据来看，也许这个人数微不足道，但对于每个不幸的家庭而言，却是百分之百的苦难。&lt;/p&gt; &lt;p&gt;套用《我不是药神》的台词：“谁家没个孩子，你就能保证你家孩子不生病吗？”&lt;/p&gt; &lt;p&gt;网上有人说：“我本以为躲过了毒奶粉，没想到躲不过毒疫苗。”除了疫苗，还有各类药品、食品、奶粉、保健品……&lt;/p&gt; &lt;p&gt;韩国人的那句嘲讽不断在耳边响起：“恭喜啊，你们在弄死自己的路上又进了一步。”我是多想有一个耳光扇死这个韩国人的底气。&lt;/p&gt; &lt;p&gt;声明：本文转载自互联网&lt;/p&gt;</content:encoded>
      <pubDate>Fri, 05 May 2017 02:30:00 GMT</pubDate>
    </item>
    <item>
      <title>什么是中产阶级陷阱？</title>
      <link>https://gitlab.520531.xyz/article/6</link>
      <content:encoded>&lt;p&gt;什么是中产阶级陷阱，在这里先引入在《穷爸爸与富爸爸》这本书里的一个概念，让大家去思考一下。     &lt;/p&gt; &lt;p&gt;富人阶级总是购买资产，中产阶级总是购买自以为是资产的负债，穷人阶级只能应付各种账单和负债。也许有人会问，什么是资产呢？这可能和会计上的资产不一样，在现金流中，所谓的资产就是可以不断增加你的现金流的物品，如果它会使你的现金流减少，那它就是负债。那什么是自以为是资产的负债呢？举个例子，小汽车和平时很少用到的高档奢侈品就是人们经常购买的自以为是资产的负债。     &lt;/p&gt; &lt;p&gt;说到这里，可能有些朋友对中产阶级陷阱会有一些自己的思考了。不同的人定义很多，我在这里说一下自己和一些朋友的观点。中产阶级陷阱就是人们不断努力工作，寻求升职加薪的机会，但是目的都是为了让生活变得更舒适，按理说这样也没错，可是很多人的做法确正是在不断购买自以为是资产的负债。为了最求舒适的生活，不断购买更大的房子，更好的小汽车，追逐各种高档奢侈品牌，希望自己的生活看起来更符合中产阶级的身份，过上了一种高资产高负债的生活状态，在升职加薪之后又会购买更多自以为是资产的负债，收入增加的同时，负债也在不断增加，总是摆脱不了这个问题，同时也是自己或者家庭抵御风险的能力变得极低。也许有人会说只要收入足够高改变这一状态，可是大家总是忽略消费曲线是一条随着收入曲线递增的函数，如果思想观念不改变，靠收入是很难改变这种现状的，至少大部分人的收入是很难达到改变这种现状的地步。&lt;/p&gt; &lt;p&gt;声明：本文转载自互联网&lt;/p&gt;</content:encoded>
      <pubDate>Sat, 19 Nov 2016 02:10:00 GMT</pubDate>
    </item>
    <item>
      <title>linux常用命令收集</title>
      <link>https://gitlab.520531.xyz/article/linux-shell-collection</link>
      <content:encoded>&lt;p&gt;&lt;strong&gt;一.设置开机自启动&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;1.赋予脚本可执行权限（/root/autostart.sh是你的脚本路径）&lt;/p&gt; &lt;p&gt;chmod +x /root/autostart.sh&lt;/p&gt; &lt;p&gt;2.打开/etc/rc.d/rc.local文件，在末尾增加如下内容&lt;/p&gt; &lt;p&gt;/root/autostart.sh&lt;/p&gt; &lt;p&gt;3.在centos7中，/etc/rc.d/rc.local的权限被降低了，所以需要执行如下命令赋予其可执行权限&lt;/p&gt; &lt;p&gt;chmod +x /etc/rc.d/rc.local&lt;/p&gt; &lt;p&gt;上述方法现在已不建议使用，更推荐使用systemd的方式。&lt;/p&gt; &lt;p&gt;第一步，创建service文件&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;vi /etc/systemd/system/myautostart.service  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;第二步，粘贴插入以下代码&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;[Unit]  Description=myautostart service  After=caddy.service  [Service]  Type=forking  ExecStart=/bin/sh /root/autostart.sh  [Install]  WantedBy=multi-user.target  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;第三步，配置服务自启动&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;开机启动：systemctl enable myautostart  启动：systemctl start myautostart  关闭：systemctl stop myautostart  重启：systemctl restart myautostart  查看状态：systemctl status myautostart  修改服务配置重新生效：systemctl daemon-reload  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&lt;strong&gt;二.清除命令记录&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;1.清除登陆系统成功的记录&lt;/p&gt; &lt;p&gt;echo &amp;gt; /var/log/wtmp&lt;/p&gt; &lt;p&gt;2.清除登陆系统失败的记录&lt;/p&gt; &lt;p&gt;echo &amp;gt; /var/log/btmp&lt;/p&gt; &lt;p&gt;3.清除历史执行命令&lt;/p&gt; &lt;p&gt;echo &amp;gt; ./.bash_history&lt;/p&gt; &lt;p&gt;&lt;span style="font-weight: 700;"&gt;三.常用命令记录&lt;/span&gt;&lt;/p&gt; &lt;p&gt;1.后台启动&lt;/p&gt; &lt;p&gt;nohup&lt;/p&gt; &lt;p&gt;2.后台启动且不输出日志&lt;/p&gt; &lt;p&gt;nohup xxx.sh 1&amp;gt;/dev/null 2&amp;gt;&amp;amp;1 &amp;amp;&lt;/p&gt; &lt;div&gt;&lt;span style="color: rgb(51, 51, 51); font-family: &amp;quot;PingFang SC&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif;"&gt;&lt;/span&gt;&lt;/div&gt; &lt;p&gt;&lt;span style="color: rgb(51, 51, 51); font-family: &amp;quot;PingFang SC&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif;"&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 51); font-family: &amp;quot;PingFang SC&amp;quot;, &amp;quot;Helvetica Neue&amp;quot;, Helvetica, Arial, sans-serif;"&gt;&lt;/span&gt;&lt;span style="color: rgb(51, 51, 51); font-family: Verdana, Arial, Helvetica, sans-serif;"&gt;&lt;/span&gt;&lt;/p&gt;</content:encoded>
      <pubDate>Tue, 18 Oct 2016 01:30:00 GMT</pubDate>
    </item>
    <item>
      <title>编程，软件配置经验积累</title>
      <link>https://gitlab.520531.xyz/article/soft-experience</link>
      <content:encoded>&lt;p&gt;&amp;lt;1&amp;gt; 可单独运行的jar，获取jar内的图片资源方法，其他资源可以类似获取&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;ImageIcon favol =new ImageIcon(xx.class.getResource(&amp;quot;/xx.jpg&amp;quot;));  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&amp;lt;2&amp;gt; c#提交post请求&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;string postData = &amp;quot;aaa=123&amp;amp;bbb=456&amp;quot;; byte[] data = encoding.GetBytes(postData); HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(sendURL); myRequest.Method = &amp;quot;POST&amp;quot;; myRequest.Timeout = 600000; myRequest.ContentType = &amp;quot;application/x-www-form-urlencoded&amp;quot;; myRequest.ContentLength = data.Length; Stream newStream = myRequest.GetRequestStream(); newStream.Write(data, 0, data.Length); newStream.Close(); &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;&amp;lt;3&amp;gt; linux禁ping----无需重启&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;sysctl -w net.ipv4.icmp_echo_ignore_all=1 sysctl -p &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Sun, 28 Aug 2016 09:50:00 GMT</pubDate>
    </item>
    <item>
      <title>Caddy反代自动https配置</title>
      <link>https://gitlab.520531.xyz/article/caddy-config</link>
      <content:encoded>&lt;p&gt;淘宝客反代配置-跳转&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;xxx.com {     tls 21371218@gmail.com     gzip     timeouts none     header / Strict-Transport-Security &amp;quot;max-age=31536000;&amp;quot;     redir  302 {       if {&amp;gt;User-agent} has Mobile          if {path} is /           https://xxx.com/index.php?r=index/wap     }     proxy / 127.0.0.1:7261 {     } }  &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;单ws反代&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;xxx.com {     tls 7517281@gmail.com     gzip     timeouts none     header / Strict-Transport-Security &amp;quot;max-age=31536000;&amp;quot;     proxy / https://xxx.com {         except /ok.htm     }     proxy /ok.htm 127.0.0.1:5214{         without /ok.htm         websocket     } } import sites/* &lt;/code&gt;&lt;/pre&gt; &lt;p&gt;网站反代&lt;/p&gt; &lt;pre&gt;&lt;code class="language-js"&gt;xxx.xxx.com {     tls 324318@gmail.com     gzip     timeouts none     header / Strict-Transport-Security &amp;quot;max-age=31536000;&amp;quot;     proxy / http://xxx.xxx.com:3231{     } } &lt;/code&gt;&lt;/pre&gt;</content:encoded>
      <pubDate>Mon, 04 Jul 2016 06:45:00 GMT</pubDate>
    </item>
  </channel>
</rss>

