<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Yqsas Blog</title>
    <description></description>
    <link>https://yqsas.com/</link>
    <atom:link href="https://yqsas.com/feed.xml" rel="self" type="application/rss+xml" />
    <pubDate>Sat, 02 Dec 2023 06:23:31 +0000</pubDate>
    <lastBuildDate>Sat, 02 Dec 2023 06:23:31 +0000</lastBuildDate>
    <generator>Jekyll v3.9.3</generator>
    
      <item>
        <title>Unity URP Shader PBR 转 BlinnPhong</title>
        <description>&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;

&lt;p&gt;项目中有一些第三方或者ASE生成的Shader代码，默认都是用的PBR光照，然而大部分材质BlinnPhong光照模型就够用了，尤其在移动端我们可以考虑优化。&lt;br /&gt;
如何使用最少的代码，将PBR使用的Metallic流程的材质参数快速转换到BlinnPhong光照呢，今天研究了一会儿效果还行，供大家参考。&lt;/p&gt;

&lt;h2 id=&quot;shader&quot;&gt;Shader&lt;/h2&gt;

&lt;div class=&quot;language-hlsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//BlinnPhong额外加强高光，贴近PBR效果。&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;UniversalFragmentBlinnPhongAddSpecular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diffuse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularGloss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothnessPower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emission&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// To ensure backward compatibility we have to avoid using shadowMask input, as it is not present in older shaders&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#if defined(SHADOWS_SHADOWMASK) &amp;amp;&amp;amp; defined(LIGHTMAP_ON)
&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#elif !defined (LIGHTMAP_ON)
&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unity_ProbesOcclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetMainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shadowCoord&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;positionWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#if defined(_SCREEN_SPACE_OCCLUSION)
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;AmbientOcclusionFactor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aoFactor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetScreenSpaceAmbientOcclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalizedScreenSpaceUV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aoFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directAmbientOcclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bakedGI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aoFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indirectAmbientOcclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;MixRealtimeAndBakedGI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bakedGI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distanceAttenuation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shadowAttenuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diffuseColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bakedGI&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LightingLambert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
&lt;/span&gt;    &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LightingSpecular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mainLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewDirectionWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularGloss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smoothnessPower&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#ifdef _ADDITIONAL_LIGHTS
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixelLightCount&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetAdditionalLightsCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;uint&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0u&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lightIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pixelLightCount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lightIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Light&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;GetAdditionalLight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lightIndex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;positionWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shadowMask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#if defined(_SCREEN_SPACE_OCCLUSION)
&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aoFactor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;directAmbientOcclusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;        &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;distanceAttenuation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shadowAttenuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;diffuseColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LightingLambert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;specularColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LightingSpecular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attenuatedLightColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;light&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;direction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;viewDirectionWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularGloss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;smoothnessPower&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#ifdef _ADDITIONAL_LIGHTS_VERTEX
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;diffuseColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vertexLighting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;finalColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diffuseColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;diffuse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emission&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR) || defined(_MASKMAP)
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;finalColor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;finalColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;//metallic、smoothness 均为采样后已混合好的结果值&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MetallicBlinnPhong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;InputData&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;metallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emission&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothnessPower&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exp2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//SimpleLit做法&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;half&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oneMinusReflectivity&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;OneMinusReflectivityMetallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;metallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;oneMinusReflectivity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specular&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kDieletricSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;metallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;specularColor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UniversalFragmentBlinnPhongAddSpecular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;specular&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rgb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;smoothnessPower&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;emission&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;对比&quot;&gt;对比&lt;/h2&gt;

&lt;p&gt;对比图偷懒就不放了🫣。&lt;/p&gt;

&lt;p&gt;我们以 URP 自带的地形着色器 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Universal Render Pipeline/Terrain/Lit&lt;/code&gt; 举个例子。&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;修改前：
    &lt;div class=&quot;language-hlsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UniversalFragmentPBR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;metallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;cm&quot;&gt;/* specular */&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;occlusion&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;cm&quot;&gt;/* emission */&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                                     &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;修改后
    &lt;div class=&quot;language-hlsl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;half4&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MetallicBlinnPhong&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;inputData&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;albedo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;metallic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;smoothness&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                  &lt;span class=&quot;kt&quot;&gt;half3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
                  &lt;span class=&quot;n&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Mon, 25 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2023/09/25/unity-urp-pbr-to-nbr/</link>
        <guid isPermaLink="true">https://yqsas.com/2023/09/25/unity-urp-pbr-to-nbr/</guid>
        
        <category>Unity</category>
        
        <category>URP</category>
        
        
      </item>
    
      <item>
        <title>折腾之 ER-X 编译尝鲜 OpenWrt</title>
        <description>&lt;p&gt;EdgeMax 虽然基于debian扩展性比较高，但是鉴于每次修改路由器配置的麻烦，还是刷成熟悉的OpenWrt，毕竟有NAS的情况下，路由器做好自己的网络管理就好了。&lt;/p&gt;

&lt;h2 id=&quot;准备环境&quot;&gt;准备环境&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;操作系统推荐 Ubuntu 18.04，避免编译依赖的问题。如果使用 win10，通过 wsl 安装也可具备环境，推荐使用这种方式。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;替换国内源&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;安装所需的依赖&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;git build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch python3 unzip zlib1g-dev lib32gcc1 libc6-dev-i386 subversion flex uglifyjs git-core gcc-multilib p7zip p7zip-full msmtp libssl-dev texinfo libglib2.0-dev xmlto qemu-utils upx libelf-dev autoconf automake libtool autopoint device-tree-compiler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;代理工具&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;
        &lt;p&gt;安装 proxychains4&lt;/p&gt;

        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo apt-get install proxychains4&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li&gt;
        &lt;p&gt;配置 proxychains4.conf&lt;/p&gt;

        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo vim /etc/proxychains4.conf&lt;/code&gt;&lt;/p&gt;

        &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;socks5 xxx.xxx.xxx.xxx 1080&lt;/code&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;git 代理配置&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; http.proxy &lt;span class=&quot;s1&quot;&gt;'socks5://xxx.xxx.xxx.xxx:1080'&lt;/span&gt;
 git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; https.proxy &lt;span class=&quot;s1&quot;&gt;'socks5://xxx.xxx.xxx.xxx:1080'&lt;/span&gt;

 &lt;span class=&quot;c&quot;&gt;# 取消代理&lt;/span&gt;
 git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--unset&lt;/span&gt; http.proxy
 git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--unset&lt;/span&gt; https.proxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;编译&quot;&gt;编译&lt;/h2&gt;

&lt;p&gt;自己编译可以只有选择需要的插件和功能，对于内存吃紧的同学来说比较有用，不想折腾的同学可以直接使用官方编译的镜像。
OpenWrt 官方镜像地址：&lt;a href=&quot;https://downloads.openwrt.org/&quot;&gt;https://downloads.openwrt.org/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;以下开始编译步骤：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git clone https://github.com/coolsnowwolf/lede&lt;/code&gt; 命令下载好源代码，然后 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd lede&lt;/code&gt; 进入目录&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./scripts/feeds update -a&lt;/code&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./scripts/feeds install -a&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;对固件功能进行配置
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make menuconfig&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Target System 选择 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MediaTek Ralink MIPS&lt;/code&gt;，Subtarget 选择&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MT7621 based boards&lt;/code&gt;，Target Profile 选择&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EdgeRouter X&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;选择自用插件、主题等。 主题使用&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;预下载编译过程所需工具&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxychains4 make download&lt;/code&gt; ；此处注意需要配置好 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxychains4&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;如果编译过程中网络问题卡住，可手动下载依赖包到 dl 文件夹：&lt;a href=&quot;https://sources.openwrt.org/&quot;&gt;https://sources.openwrt.org/&lt;/a&gt;。&lt;/li&gt;
      &lt;li&gt;提供我编译过程总用到的依赖文件，解压后文件放在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lede/dl&lt;/code&gt; 路径下即可。需要的同学自取： 链接: &lt;a href=&quot;https://pan.baidu.com/s/1jBgBXaSLkk8wM35lpMFpcw&quot;&gt;lede-dl.zip&lt;/a&gt; 提取码: tb92。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;开始编译：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make -j1 V=s&lt;/code&gt;（-j1 后面是线程数。第一次编译推荐用单线程，国内请尽量全局科学上网）即可开始编译你要的固件了。如果过程中因为网络问题卡住，也建议加上 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxychains4&lt;/code&gt; 代理&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;编译完成，在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lede/bin/targets/ramips/mt7621&lt;/code&gt; 下找到编译生成的文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openwrt-ramips-mt7621-ubiquiti_edgerouterx-initramfs-kernel.bin&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;openwrt-ramips-mt7621-ubiquiti_edgerouterx-squashfs-sysupgrade.bin&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;安装&quot;&gt;安装&lt;/h2&gt;

&lt;p&gt;编译结果从 19.x 版本后不支持生成 tar 版的内核镜像包，实际编译结果是 initramfs-kernel.bin ，据说是由于后续内核超过一定大小的原因。而 bin 类型的内核刷机较复杂，需要连接 TTL 线或者在 uboot 下刷入。
所以接下来我们使用一个只需 ssh 的简单的方式，就是在网上找一个 18.x 版本的内核 tar 包，刷入内核成功后，再用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysupgrade&lt;/code&gt; 升级安装系统，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysupgrade&lt;/code&gt; 可以使用 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bin&lt;/code&gt; 文件。&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;18.x 的内核 tar 文件，可使用 &lt;a href=&quot;https://www.right.com.cn/forum/thread-338384-1-1.html&quot;&gt;UBNT-ER-X 刷机教程-openwrt&lt;/a&gt; 帖子中的附件。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;上传&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubnt-erx-squashfs-factory-initramfs.tar&lt;/code&gt;到 ERX 原版系统的/tmp 下面&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;用 ssh 登录进原版系统，输入命令&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add system image openwrt-ramips-mt7621-ubnt-erx-squashfs-factory-initramfs.tar&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;输入 reboot 重启路由器&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;用 ssh 登录路由器，网线连接路由器，默认没有密码，现在应该已经是 openwrt 了，上传 squashfs-sysupgrade.bin 到路由器 /tmp 目录里，
再运行 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sysupgrade squashfs-sysupgrade.bin&lt;/code&gt; 完成后系统会自动重启，等待即可。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;再次连上路由器，就可以进入路由器了网页界面了&lt;/p&gt;
    &lt;blockquote&gt;
      &lt;p&gt;默认地址：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http(s)://192.168.1.1&lt;/code&gt;，默认用户&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root&lt;/code&gt;，默认密码 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt;。&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;参考链接&quot;&gt;参考链接&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://downloads.openwrt.org/&quot;&gt;https://downloads.openwrt.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/coolsnowwolf/lede&quot;&gt;https://github.com/coolsnowwolf/lede&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://sources.openwrt.org/&quot;&gt;https://sources.openwrt.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.jianshu.com/p/eed71e8a22cc&quot;&gt;OpenWrt/LEDE 编译小记（斐讯 K2P）&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.right.com.cn/forum/thread-338384-1-1.html&quot;&gt;UBNT-ER-X 刷机教程-openwrt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 21 Feb 2020 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2020/02/21/compile-and-install-openwrt-in-ubnt-erx/</link>
        <guid isPermaLink="true">https://yqsas.com/2020/02/21/compile-and-install-openwrt-in-ubnt-erx/</guid>
        
        <category>折腾</category>
        
        
      </item>
    
      <item>
        <title>Spring Cloud 项目国际化</title>
        <description>&lt;h2 id=&quot;spring-cloud-项目国际化&quot;&gt;Spring Cloud 项目国际化&lt;/h2&gt;

&lt;h3 id=&quot;0-前言&quot;&gt;0. 前言&lt;/h3&gt;

&lt;p&gt;最近几天给项目做了国际化相关工作，以此记录。&lt;/p&gt;

&lt;p&gt;Spring Boot 默认就支持国际化，而且不需要我们过多的做什么配置，只需要在 resources/下定义国际化配置文件即可，注意名称必须以 messages 开头。
但是考虑到配置管理以及自定义解析需求，一般还是另外自定义配置类。&lt;/p&gt;

&lt;p&gt;原理是读取国际化配置文件，以 &lt;strong&gt;编码=内容&lt;/strong&gt; 为映射记录。当收到一个请求时，使用配置的 LocaleResolver 解析当前请求语言，
最后使用 MessageSource 获取编码映射的实际语言内容。&lt;/p&gt;

&lt;p&gt;Demo 代码 github 地址：&lt;a href=&quot;https://github.com/yqsas/spring-cloud-i18n-demo&quot;&gt;https://github.com/yqsas/spring-cloud-i18n-demo&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;1-spring-国际化配置&quot;&gt;1. Spring 国际化配置&lt;/h3&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;spring&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;messages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;encoding&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;UTF-8&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;i18n/messages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;2-国际化语言配置文件&quot;&gt;2. 国际化语言配置文件&lt;/h3&gt;

&lt;p&gt;在 resources 下创建 i18n 目录，并在其中新建文件：messages.properties、messages_en_US.properties、messages_zh_CN.properties。
，注意以 messages 开头。&lt;/p&gt;

&lt;p&gt;配置文件中填写 &lt;strong&gt;编码=内容&lt;/strong&gt; 形式的映射记录。&lt;/p&gt;

&lt;p&gt;如：
messages_en_US.properties&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;user.welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Welcome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;messages_zh_CN.properties&lt;/p&gt;

&lt;div class=&quot;language-properties highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;py&quot;&gt;user.welcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;欢迎&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;3-自定义语言区域解析器&quot;&gt;3. 自定义语言区域解析器&lt;/h3&gt;

&lt;p&gt;Spring 在 org.springframework.web.servlet.i18n 包下，提供默认几种语言区域解析器：CookieLocaleResolver、AcceptHeaderLocaleResolver、
FixedLocaleResolver、SessionLocaleResolver 等，几种方式顾名思义，各有用途。&lt;/p&gt;

&lt;p&gt;但是在 Spring Cloud 体系中，我们用到 OAuth2 作为鉴权机制，后端无 Session 可用，所以首先排除 SessionLocaleResolver；
其次微服务之间接口调用使用的 Feign，无法传递 Cookie，所以也排除 CookieLocaleResolver；
并且 AcceptHeaderLocaleResolver 使用 Header 中的 &lt;strong&gt;“Accept-Language”&lt;/strong&gt; 属性来判断客户端语言环境，排除。&lt;/p&gt;

&lt;p&gt;最终确定自定义语言区域解析器，使用请求头中自定义属性作为解析依据。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleHeaderLocaleResolver&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleContextResolver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleHeaderLocaleResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.LOCALE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TIME_ZONE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleHeaderLocaleResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;.TIME_ZONE&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;localeHeadName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;localeHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;defaultLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;defaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;defaultTimeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;defaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resolveLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parseLocaleHeaderIfNecessary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleContext&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;resolveLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;parseLocaleHeaderIfNecessary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;TimeZoneAwareLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TIME_ZONE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServletResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleContext&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;notNull&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;HttpServletResponse is required for LocaleHeaderLocaleResolver&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localeContext&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localeContext&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZoneAwareLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;TimeZoneAwareLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;determineDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TIME_ZONE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;determineDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parseLocaleHeaderIfNecessary&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

            &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;headName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getHeader&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;headName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localePart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZonePart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
                    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spaceIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localePart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;' '&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spaceIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;localePart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spaceIndex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;timeZonePart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;substring&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;spaceIndex&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;equals&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localePart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parseLocaleValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localePart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeZonePart&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringUtils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;parseTimeZoneString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeZonePart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;IllegalArgumentException&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;WebUtils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ERROR_EXCEPTION_ATTRIBUTE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;c1&quot;&gt;// Error dispatch: ignore locale/timezone parse exceptions&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                            &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;IllegalStateException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Invalid locale Header '&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                                &lt;span class=&quot;s&quot;&gt;&quot;' with value [&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeStr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;]: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getMessage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
                        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

            &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCALE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;determineDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;TIME_ZONE_REQUEST_ATTRIBUTE_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeZone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;determineDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)));&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;determineDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TimeZone&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;determineDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getDefaultTimeZone&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parseLocaleValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;StringUtils&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;parseLocaleString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;setLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;HttpServletRequest&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;HttpServletResponse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;@Nullable&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;setLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SimpleLocaleContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;4-国际化配置类&quot;&gt;4. 国际化配置类&lt;/h3&gt;

&lt;p&gt;使用自定义区域解析类。&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Configuration&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleConfig&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;LOCAL_HEAD_NAME&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Locale&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleResolver&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;localeResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;LocaleHeaderLocaleResolver&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeResolver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleHeaderLocaleResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;localeResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setLocaleHeadName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCAL_HEAD_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;localeResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setDefaultLocale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Locale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;SIMPLIFIED_CHINESE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;WebMvcConfigurer&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;localeInterceptor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;WebMvcConfigurer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
            &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;addInterceptors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;InterceptorRegistry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nc&quot;&gt;LocaleChangeInterceptor&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;localeInterceptor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LocaleChangeInterceptor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;localeInterceptor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setParamName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LOCAL_HEAD_NAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;registry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addInterceptor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;localeInterceptor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;5-其他&quot;&gt;5. 其他&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;配合 Feign 使用，需要 Feign 配置转发请求 Header；&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;工具类提供静态方法获取当前请求线程时区，以及编码内容映射转换；&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;前端配合使用用户信息中的 lang 属性，设置当前用户使用的语言，在所有请求头中使用我们自定义属性 &lt;strong&gt;“Locale”&lt;/strong&gt; 与后端交互。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Sat, 18 May 2019 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2019/05/18/spring-cloud-i18n/</link>
        <guid isPermaLink="true">https://yqsas.com/2019/05/18/spring-cloud-i18n/</guid>
        
        <category>i18n</category>
        
        <category>Spring Cloud</category>
        
        
      </item>
    
      <item>
        <title>如何开发 fork 的 Golang 项目</title>
        <description>&lt;h2 id=&quot;如何开发-fork-的-golang-项目&quot;&gt;如何开发 fork 的 Golang 项目&lt;/h2&gt;

&lt;h3 id=&quot;问题&quot;&gt;问题&lt;/h3&gt;

&lt;p&gt;Go 基于位置的包导入机制，使得我们自己 fork 下来的项目进行二次开发时，会发现 fork 中导入的包路径依旧是源项目路径。于是我如果要正常运行的话就得把对应路径改成自己的 fork repo，接着开发完做 pull request 的时候又得修改回来，这显然是一个错误的做法。&lt;/p&gt;

&lt;h3 id=&quot;解决方式&quot;&gt;解决方式&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;打开心仪的源 repo 地址，点击 fork 按钮&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;go get 源 repo&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go get github.com/xx/xxxx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;进入目录&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src/github.com/xx/xxxx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;添加 fork 仓库源并更新&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git remote add fork git@github.com:xx/xxxx.git

git fetch fork
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;设置当前分支跟踪远程的 fork 分支&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git branch &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; fork/master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;在 ide 打开这个目录开始愉快地开发吧 :)&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;参考&quot;&gt;参考&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://dev.to/loderunner/working-with-forks-in-go-3ab6&quot;&gt;Working with forks in Go&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Thu, 21 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2019/03/21/how-to-develop-forked-go-project/</link>
        <guid isPermaLink="true">https://yqsas.com/2019/03/21/how-to-develop-forked-go-project/</guid>
        
        <category>Golang</category>
        
        
      </item>
    
      <item>
        <title>折腾之 Manjaro 安装使用指北</title>
        <description>&lt;h2 id=&quot;一前言&quot;&gt;一、前言&lt;/h2&gt;

&lt;p&gt;记录一下使用 manjaro 的过程，一方面备忘，另一方面希望可以帮助到需要的人，内容持续更新。&lt;/p&gt;

&lt;h2 id=&quot;二安装&quot;&gt;二、安装&lt;/h2&gt;

&lt;p&gt;安装过程简单说，Manjaro 安装非常简单，基本上开箱即用，和其他系统区别不大。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;下载 ISO 镜像，&lt;a href=&quot;https://manjaro.org/download/&quot;&gt;官网地址&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;制作 U 盘启动盘，强烈推荐 &lt;a href=&quot;https://github.com/ventoy/Ventoy/releases&quot;&gt;Ventoy&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;U 盘启动安装界面，时区设置为 Asia/Shanghai，语言选择 zh_CN，driver 选择 nonfree。选择 Boot 启动安装；&lt;/li&gt;
  &lt;li&gt;进入桌面（此时系统还在 U 盘中，可以体验桌面效果），双击桌面 Install Manjaro Linux 进入系统安装，然后一路按自己需求 next；&lt;/li&gt;
  &lt;li&gt;双系统情况下，注意分区选择自定义分区，然后分配 Manjaro 系统分区挂在为/（内存大不需要 swap 分区，一般使用不需要给/home 独立分区，后期调整系统大小也方便），启动分区选择已存在的 EFI system partition，挂在为/boot/efi，并选择保留（默认选项）。&lt;/li&gt;
  &lt;li&gt;安装完成后重启系统即可。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;三基本配置&quot;&gt;三、基本配置&lt;/h2&gt;

&lt;h3 id=&quot;31-软件包管理配置&quot;&gt;3.1 软件包管理配置&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#国内源，可多次尝试选择速度最快的&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman-mirrors &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; China &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; rank
&lt;span class=&quot;c&quot;&gt;#系统更新&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-Syyu&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# 配置 archlinux 软件仓库&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vim /etc/pacman.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;archlinuxcn]
  Server &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; https://mirrors.cloud.tencent.com/archlinuxcn/&lt;span class=&quot;nv&quot;&gt;$arch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-Sy&lt;/span&gt; archlinuxcn-keyring
  &lt;span class=&quot;c&quot;&gt;# AUR 包管理工具&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; yay
  &lt;span class=&quot;c&quot;&gt;# 必备工具&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; git vim net-tools base-devel
  &lt;span class=&quot;c&quot;&gt;# 解决双系统时间不同步问题&lt;/span&gt;
  timedatectl set-local-rtc &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;32-zshoh-my-zsh&quot;&gt;3.2 zsh/oh-my-zsh&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; zsh
  &lt;span class=&quot;c&quot;&gt;# curl 使用代理: curl -x &quot;127.0.0.1:7890&quot;&lt;/span&gt;
  sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# chsh -s /bin/zsh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c&quot;&gt;# 必备插件安装&lt;/span&gt;
  git clone https://github.com/zsh-users/zsh-completions &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZSH_CUSTOM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;~/.oh-my-zsh/custom&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/plugins/zsh-completions

  git clone https://github.com/zsh-users/zsh-syntax-highlighting.git &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZSH_CUSTOM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;~/.oh-my-zsh/custom&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/plugins/zsh-syntax-highlighting

  git clone https://github.com/zsh-users/zsh-autosuggestions.git &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ZSH_CUSTOM&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;~/.oh-my-zsh/custom&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;/plugins/zsh-autosuggestions

  vim ~/.zshrc
  &lt;span class=&quot;c&quot;&gt;# edit plugins &amp;amp; save&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=(&lt;/span&gt;git zsh-syntax-highlighting docker docker-compose zsh-autosuggestions zsh-completions&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;

  autoload &lt;span class=&quot;nt&quot;&gt;-U&lt;/span&gt; compinit &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; compinit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;33-中文输入法&quot;&gt;3.3 中文输入法&lt;/h3&gt;

&lt;p&gt;使用fcitx5即可。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;配置使用 fcitx 输入法&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vim /etc/profile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;GTK_IM_MODULE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fcitx5
 &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;QT_IM_MODULE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fcitx5
 &lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;XMODIFIERS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;@im&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;fcitx5
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;安装输入法&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; fcitx5 fcitx5-qt fcitx5-gtk fcitx5-configtool fcitx5-gtk fcitx5-qt
 &lt;span class=&quot;c&quot;&gt;#拼音输入法&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; fcitx5-chinese-addons fcitx5-pinyin-zhwiki
 &lt;span class=&quot;c&quot;&gt;#主题&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; fcitx5-pinyin-zhwiki fcitx5-material-color
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;blockquote&gt;
      &lt;p&gt;主题设置：前往 Fcitx5设置 -&amp;gt; 配置附加组件 -&amp;gt; 经典用户界面 -&amp;gt; 主题&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;34-必备字体安装&quot;&gt;3.4 必备字体安装&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; wqy-bitmapfont wqy-microhei &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  wqy-zenhei adobe-source-code-pro-fonts &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  adobe-source-sans-pro-fonts adobe-source-serif-pro-fonts &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  adobe-source-han-sans-cn-fonts ttf-monaco ttf-dejavu ttf-hanazono &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  noto-fonts noto-fonts-cjk noto-fonts-emoji
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;35-双显卡配置&quot;&gt;3.5 双显卡配置&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;更换默认驱动&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; virtualgl lib32-virtualgl lib32-primus primus

 &lt;span class=&quot;c&quot;&gt;# 查看当前已安装驱动&lt;/span&gt;
 mhwd &lt;span class=&quot;nt&quot;&gt;-li&lt;/span&gt;
 &lt;span class=&quot;c&quot;&gt;# 卸载不需要的驱动&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mhwd &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; pci video-hybrid-intel-nvidia-418xx-bumblebee
 &lt;span class=&quot;c&quot;&gt;# 安装最新闭源驱动&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mhwd-tui &lt;span class=&quot;c&quot;&gt;# 选择4&lt;/span&gt;

 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;bumblebeed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;用户组设置&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c&quot;&gt;#添加 bumblebee 用户组&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;groupadd bumblebee
 &lt;span class=&quot;c&quot;&gt;#添加当前用户到该组&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gpasswd &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt; bumblebee
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;重启电脑&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;36-vpn-客户端配置&quot;&gt;3.6 VPN 客户端配置&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;系统默认未安装客户端，需要先行安装客户端支持。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;L2TP 客户端安装&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c&quot;&gt;# 安装 strongswan  原因：need strongswan (or libreswan) for IPSec support.&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; strongswan
 &lt;span class=&quot;c&quot;&gt;# 安装 l2tp 依赖&lt;/span&gt;
 yay &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; libnm-git
 &lt;span class=&quot;c&quot;&gt;# 安装 l2tp 客户端，先选 2 一遍安装一些依赖，再选 1 一遍编译安装&lt;/span&gt;
 yay &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; networkmanager-l2tp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;控制命令&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c&quot;&gt;# 获取所有 vpn 连接列表&lt;/span&gt;
 nmcli con show
 &lt;span class=&quot;c&quot;&gt;# 连接一个标记为已断开的网络接口&lt;/span&gt;
 nmcli con up &amp;lt;uuid/name&amp;gt;
 &lt;span class=&quot;c&quot;&gt;# 断开一个网络连接&lt;/span&gt;
 nmcli con down &amp;lt;uuid/name&amp;gt;
 &lt;span class=&quot;c&quot;&gt;# 添加内网路由&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;route add &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; 10.0.0.0 netmask 255.0.0.0 gw &amp;lt;gateway ip&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;四开发环境&quot;&gt;四、开发环境&lt;/h2&gt;

&lt;h3 id=&quot;41-docker&quot;&gt;4.1 Docker&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; docker docker-compose

  &lt;span class=&quot;c&quot;&gt;# 设置普通用户使用 Docker 不需要使用 sudo&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;groupadd docker
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;usermod &lt;span class=&quot;nt&quot;&gt;-aG&lt;/span&gt; docker &lt;span class=&quot;nv&quot;&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;42-ide编辑器&quot;&gt;4.2 IDE/编辑器&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c&quot;&gt;# snap&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; snapd
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--now&lt;/span&gt; snapd.socket
  &lt;span class=&quot;nb&quot;&gt;sudo ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /var/lib/snapd/snap /snap
  &lt;span class=&quot;c&quot;&gt;# IDEA&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;snap &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;intellij-idea-ultimate &lt;span class=&quot;nt&quot;&gt;--classic&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# rider&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;snap &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;rider &lt;span class=&quot;nt&quot;&gt;--classic&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;# vscode&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; vscode
  &lt;span class=&quot;c&quot;&gt;# datagrip 数据库管理&lt;/span&gt;
  yay &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; datagrip
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; mysql-workbench
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;43-java-环境&quot;&gt;4.3 Java 环境&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; maven
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;44-nodejs-环境&quot;&gt;4.4 Nodejs 环境&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; nodejs npm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;45-rubyjekyll&quot;&gt;4.5 Ruby+Jekyll&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c&quot;&gt;# Ruby&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; ruby
  gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jekyll bundler
  &lt;span class=&quot;c&quot;&gt;#项目依赖安装：bundle install/update&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;46-其他&quot;&gt;4.6 其他&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c&quot;&gt;# pip&lt;/span&gt;
  yay &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; python-pip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;五软件推荐&quot;&gt;五、软件推荐&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# 日常&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; google-chrome

  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; netease-cloud-music
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; filezilla  &lt;span class=&quot;c&quot;&gt;# FTP/SFTP&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; virtualbox  virtualbox-guest-dkms &lt;span class=&quot;c&quot;&gt;# 选择当前内核对应版本&lt;/span&gt;

  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; goldendict &lt;span class=&quot;c&quot;&gt;# 翻译、取词&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# 不推荐有道词典 高分屏坐标偏移，屏幕取词不便&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# [英汉字典下载](https://github.com/skywind3000/ECDICT/releases)&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# 多平台笔记应用，替代印象笔记&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; joplin

  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; linuxqq             &lt;span class=&quot;c&quot;&gt;#qq&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; deepin-wine-wechat  &lt;span class=&quot;c&quot;&gt;# 微信&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 开发&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; tmux

&lt;span class=&quot;c&quot;&gt;# 办公&lt;/span&gt;
  &lt;span class=&quot;c&quot;&gt;#字体切记采用这种方式安装&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; ttf-wps-fonts wps-office wps-office-mui-zh-cn

&lt;span class=&quot;c&quot;&gt;# 装 X&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; neofetch
    &lt;span class=&quot;c&quot;&gt;#配合食用：neofetch --ascii_distro arch&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; screenfetch
    &lt;span class=&quot;c&quot;&gt;#配合食用：screenfetch -A 'Arch Linux'&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# 其他&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; light &lt;span class=&quot;c&quot;&gt;# 命令调节亮度&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; guake &lt;span class=&quot;c&quot;&gt;# 下拉终端，同类：tilda&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; sshpass &lt;span class=&quot;c&quot;&gt;# 指定密码登录ssh： sshpass -p passwd ssh user@xx.xx.xx.xx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;六桌面环境&quot;&gt;六、桌面环境&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;2019.12 更新： manjaro 官网 Deepin 环境已经消失，不建议继续使用&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;目前使用过 KDE、Gnome、Deepin 三种桌面环境。KDE 界面特效多、自定义程度高，Gnome 简洁直观，建议大家按需选择。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;安装 KDE&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; plasma kio-extras
 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; kdebase

 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;pacman &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; manjaro-kde-settings sddm-breath-theme manjaro-settings-manager-knotifier manjaro-settings-manager-kcm

 &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;systemctl &lt;span class=&quot;nb&quot;&gt;enable &lt;/span&gt;sddm.service &lt;span class=&quot;nt&quot;&gt;--force&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;七其他记录&quot;&gt;七、其他记录&lt;/h2&gt;

&lt;h3 id=&quot;71-hidpi-配置&quot;&gt;7.1 Hidpi 配置&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;xorg 配置缩放
    &lt;blockquote&gt;
      &lt;p&gt;参考文档： &lt;a href=&quot;https://wiki.archlinux.org/index.php/HiDPI_（简体中文）&quot;&gt;HiDPI （简体中文）&lt;/a&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
    &lt;ul&gt;
      &lt;li&gt;在 设置 –&amp;gt; 设备 –&amp;gt; 显示器中，缩放设置为 200%（缩放倍率可以按整数倍率调整，但是容易出现 1 倍太小，2 倍太大的情况）&lt;/li&gt;
      &lt;li&gt;利用 xrandr 微调合适倍率： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xrandr --output eDP1 --scale 1.2x1.2&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;命令启动时执行： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim /etc/profile&lt;/code&gt;，在文件最后添加上一条命令内容&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;chrome&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;vim /usr/share/applications/google-chrome.desktop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;div class=&quot;language-vim highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; # 这一行修改
 Exec&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/usr/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;bin&lt;/span&gt;/google&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;chrome&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;stable %U
 # 添加启动命令参数
 Exec&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/usr/&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;bin&lt;/span&gt;/google&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;chrome&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;stable &lt;span class=&quot;p&quot;&gt;--&lt;/span&gt;force&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;device&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;scale&lt;span class=&quot;p&quot;&gt;-&lt;/span&gt;factor&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;7&lt;/span&gt; %U
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;wine 安装的软件&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nv&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/.deepinwine/&amp;lt;你的 APP 目录&amp;gt; wine winecfg
 &lt;span class=&quot;c&quot;&gt;#或者&lt;/span&gt;
 &lt;span class=&quot;nv&quot;&gt;WINEPREFIX&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~/.deepinwine/&amp;lt;你的 APP 目录&amp;gt; deepin-wine winecfg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;72-科学上网&quot;&gt;7.2 科学上网&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;和windows一样的GUI版本：
    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  yay -S clash-for-windows-bin
  #启动
  sudo cfw  --no-sandbox
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;使用 docker 启动 clash 的方式，由 clash 进行全局代理，根据自定义规则选择上网方式。
    &lt;ol&gt;
      &lt;li&gt;启动 clash 容器
 准备 docker-compose 文件：&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim ~/.config/clash/docker-compose.yml&lt;/code&gt;&lt;/li&gt;
    &lt;/ol&gt;

    &lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;3'&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;clash&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;dreamacro/clash&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;~/.config/clash/config.yaml:/root/.config/clash/config.yaml&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# dashboard volume&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# - ./ui:/ui&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;7890:7890&quot;&lt;/span&gt;
        &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;7891:7891&quot;&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# If you need external controller, you can export this port.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# - &quot;9090:9090&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;restart&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;always&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# When your system is Linux, you can use `network_mode: &quot;host&quot;` directly.&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;network_mode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;host&quot;&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;clash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;启动： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker-compose -f ~/.config/clash/docker-compose.yml up -d&lt;/code&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;准备配置文件&lt;/p&gt;

    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vim ~/.config/clash/config.yaml&lt;/code&gt;&lt;/p&gt;

    &lt;p&gt;配置文件模板请参考：&lt;a href=&quot;https://github.com/Hackl0us/SS-Rule-Snippet/blob/master/LAZY_RULES/clash.yaml&quot;&gt;Hackl0us/SS-Rule-Snippet/clash.yaml&lt;/a&gt;&lt;/p&gt;

    &lt;p&gt;根据模板，添加代理服务器配置，策略组需要增加一个名称为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Proxy&lt;/code&gt;的配置。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;配置全局代理&lt;/p&gt;

    &lt;p&gt;进入系统设置 –&amp;gt; 网络 –&amp;gt; 网络代理 –&amp;gt; 手动。&lt;/p&gt;
    &lt;ul&gt;
      &lt;li&gt;http(s) 配置： 127.0.0.1:7890&lt;/li&gt;
      &lt;li&gt;socket 配置： 127.0.0.1:7891&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;73-常用命令&quot;&gt;7.3 常用命令&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  lspci|grep &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; net &lt;span class=&quot;c&quot;&gt;#查看网卡信息&lt;/span&gt;

  systemctl list-unit-files &lt;span class=&quot;nt&quot;&gt;--state&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;enabled &lt;span class=&quot;c&quot;&gt;#查看已经启用的服务&lt;/span&gt;
  systemd-analyze critical-chain xxx.service &lt;span class=&quot;c&quot;&gt;#查看关联性服务启动耗费时间&lt;/span&gt;
  systemd-analyze blame &lt;span class=&quot;c&quot;&gt;#按时间排序，查看服务启动耗费时间&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# git 代理设置，推荐放到 .zshrc 中作为常用命令&lt;/span&gt;
  git-proxy&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
    git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; http.proxy socks5://127.0.0.1:1080
    git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; https.proxy socks5://127.0.0.1:1080
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  git-noproxy&lt;span class=&quot;o&quot;&gt;(){&lt;/span&gt;
    git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--unset&lt;/span&gt; http.proxy
    git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--unset&lt;/span&gt; https.proxy
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Sun, 03 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2019/03/03/manjaro-install/</link>
        <guid isPermaLink="true">https://yqsas.com/2019/03/03/manjaro-install/</guid>
        
        <category>折腾</category>
        
        <category>manjaro</category>
        
        <category>linux</category>
        
        
      </item>
    
      <item>
        <title>我的 Markdown 写作最佳实践</title>
        <description>&lt;h2 id=&quot;我的-markdown-使用方式记录&quot;&gt;我的 Markdown 使用方式记录&lt;/h2&gt;

&lt;p&gt;Markdown 为广大群众喜爱的原因有许多，最关键的就是其文本格式可以随处发布，并保持原始排版。但是五花八门的 Markdown 编辑器实现各异，不规范地使用语法容易导致迁移平台时排版混乱。&lt;/p&gt;

&lt;p&gt;以下都是基于个人喜爱，仅供参考。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;各平台使用 &lt;strong&gt;印象笔记、Joplin&lt;/strong&gt; 同步素材以及没有完成的文章&lt;/li&gt;
  &lt;li&gt;写作使用 &lt;strong&gt;Visual Studio Code&lt;/strong&gt; 软件&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;插件安装 &lt;strong&gt;Markdown All in One&lt;/strong&gt;&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;根据需要配置想要的版本和功能支持，快捷键丰富，效率神器。预览效果也不错。&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;语法检查安装 &lt;strong&gt;markdownlint&lt;/strong&gt; ，实时语法检查对于 IDE 来说是必备的&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;使用 &lt;strong&gt;Pangu-Markdown&lt;/strong&gt; 插件检查中文排版&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;检查中英文混排效果是否符合通用实践。&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
  &lt;li&gt;导出 pdf 安装 &lt;strong&gt;Markdown PDF&lt;/strong&gt; 插件&lt;/li&gt;
  &lt;li&gt;图床使用七牛云&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Mon, 11 Feb 2019 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2019/02/11/my-blog-markdown-best-practices/</link>
        <guid isPermaLink="true">https://yqsas.com/2019/02/11/my-blog-markdown-best-practices/</guid>
        
        <category>blog</category>
        
        <category>markdown</category>
        
        
      </item>
    
      <item>
        <title>译 | 揭秘 Docker 镜像</title>
        <description>&lt;p&gt;原文：&lt;a href=&quot;https://cameronlonsdale.com/2018/11/26/whats-in-a-docker-image/&quot;&gt;What’s in a Docker image?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docker 镜像里有什么？这是一个非常好的问题，在知道答案之前，Docker 镜像看起来似乎非常神秘。现在我不仅仅将告诉你答案，并且还会告诉你我是如何得到这个答案的。&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;从-dockerfile-到镜像&quot;&gt;从 Dockerfile 到镜像&lt;/h2&gt;

&lt;p&gt;在开始之前，我假设你对于 Dockerfile 已经非常熟悉：Docker 通过 Dockerfile 说明如何构建一个镜像。下面是一个例子。&lt;/p&gt;

&lt;div class=&quot;language-Dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ubuntu:15.04&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; app.py /app&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; python /app/app.py&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dockerfile 里的每一行都是 Docker 如何构建镜像的说明。它将使用&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubuntu:15.04&lt;/code&gt;作为基础，然后复制一个 python 脚本。&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CMD&lt;/code&gt;指令是关于运行容器时要做什么的指令（将镜像转换为正在运行的进程），暂时按下不表。&lt;/p&gt;

&lt;p&gt;然后我们运行&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker build .&lt;/code&gt; 并检查输出。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; my_test_image &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Sending build context to Docker daemon  364.2MB
Step 1/3 : FROM ubuntu:15.04
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; d1b55fd07600
Step 2/3 : COPY app.py /app/
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 44ab3f1d4cd6
Step 3/3 : CMD python /app/app.py
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Running &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;c037c981012e
Removing intermediate container c037c981012e
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 174b1e992617
Successfully built 174b1e992617
Successfully tagged my_test_image:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;首先看最后两行，我们已经成功构建了一个 Docker 镜像，可以通过标识符&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;174b1e992617&lt;/code&gt;（这个值是镜像内容的 SHA256 哈希片段）找到对应镜像。&lt;/p&gt;

&lt;p&gt;我们已经得到了最终镜像，但是控制台输出独立步骤的 ID 又代表了什么？&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d1b55fd07600&lt;/code&gt; 和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;44ab3f1d4cd6&lt;/code&gt;? 它们也是镜像吗？确实如此。如果我们从 Dockerfile 中删除第 2 步（&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COPY app.py / app&lt;/code&gt;），Docker 仍然可以成功构建它作为镜像。所以镜像构建过程中的每一步，我们都得到一个镜像。&lt;/p&gt;

&lt;p&gt;这告诉我们镜像可以建立在彼此之上！当考虑&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;中的&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM&lt;/code&gt;指令只是说明要在哪个镜像上构建时，这是有道理的。&lt;/p&gt;

&lt;p&gt;一个镜像的结构必须以这样一种方式来组织，但是如何组织呢？接下来我们将把 docker 镜像拆开来看看。&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;导出镜像并解压缩&quot;&gt;导出镜像并解压缩&lt;/h2&gt;

&lt;p&gt;为了简化使用，镜像可以作为独立文件导出，这便于我们看到镜像里面的内容。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker save my_test_image &amp;gt; my_test_image&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;查看导出的文件。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;file my_test_image
my_test_image: POSIX &lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;archive
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;一个压缩包！我们解压看看。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;unpacked_image
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tar&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-xvf&lt;/span&gt; my_test_image &lt;span class=&quot;nt&quot;&gt;-C&lt;/span&gt; unpacked_image
x 174b1e9926177b5dfd22981ddfab78629a9ce2f05412ccb1a4fa72f0db21197b.json
x 28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114/
x 28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114/VERSION
x 28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114/json
x 28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114/layer.tar
x 4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e/
x 4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e/VERSION
x 4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e/json
x 4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e/layer.tar
x 6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373/
x 6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373/VERSION
x 6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373/json
x 6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373/layer.tar
x c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c/
x c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c/VERSION
x c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c/json
x c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c/layer.tar
x cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb/
x cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb/VERSION
x cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb/json
x cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb/layer.tar
x manifest.json
x repositories
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我们从&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;manifest.json&lt;/code&gt;文件开始研究。&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;174b1e9926177b5dfd22981ddfab78629a9ce2f05412ccb1a4fa72f0db21197b.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;RepoTags&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;my_test_image:latest&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;Layers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb/layer.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114/layer.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e/layer.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c/layer.tar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373/layer.tar&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;清单（manifest）文件是一段元数据，它准确描述了该镜像中的内容。我们可以看到该镜像被标记为&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_test_image&lt;/code&gt;，并且还有一些叫做&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Layers&lt;/code&gt;和&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Config&lt;/code&gt;的内容（层与配置）。&lt;/p&gt;

&lt;p&gt;JSON 配置文件的前 12 个字符正好与我们构建过程中看到的镜像 ID 相同，这可不是巧合哦。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;174b1e9926177b5dfd22981ddfab78629a9ce2f05412ccb1a4fa72f0db21197b.json
&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s2&quot;&gt;&quot;architecture&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;amd64&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Hostname&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;d2d404286fc4&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Domainname&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;User&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStdin&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStdout&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStderr&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Tty&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;OpenStdin&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;StdinOnce&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Env&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Cmd&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;-c&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;python /app/app.py&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;ArgsEscaped&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Image&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;sha256:44ab3f1d4cd69d84c9c67187b378b1d1322b5fddf4068c11e8b11856ced7efc0&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Volumes&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;WorkingDir&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Entrypoint&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;OnBuild&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;Labels&quot;&lt;/span&gt;: null
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;container&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;c037c981012e8f03ac5466fcdda8f78a14fb9bb5ee517028c66915624a5616fa&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;container_config&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;Hostname&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;d2d404286fc4&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Domainname&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;User&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStdin&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStdout&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;AttachStderr&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Tty&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;OpenStdin&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;StdinOnce&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Env&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Cmd&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;-c&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;#(nop) &quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;CMD [&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/bin/sh&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;python /app/app.py&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;ArgsEscaped&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Image&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;sha256:44ab3f1d4cd69d84c9c67187b378b1d1322b5fddf4068c11e8b11856ced7efc0&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Volumes&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;WorkingDir&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;Entrypoint&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;OnBuild&quot;&lt;/span&gt;: null,
    &lt;span class=&quot;s2&quot;&gt;&quot;Labels&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2018-11-01T03:19:16.8517953Z&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;docker_version&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;18.09.0-ce-beta1&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;history&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2016-01-26T17:48:17.324409116Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c #(nop) ADD file:3f4708cf445dc1b537b8e9f400cb02bef84660811ecdb7c98930f68fee876ec4 in /&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2016-01-26T17:48:31.377192721Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c echo '#!/bin/sh' &amp;gt; /usr/sbin/policy-rc.d &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'exit 101' &amp;gt;&amp;gt; /usr/sbin/policy-rc.d &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; chmod +x /usr/sbin/policy-rc.d &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; dpkg-divert --local --rename --add /sbin/initctl &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; cp -a /usr/sbin/policy-rc.d /sbin/initctl &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; sed -i 's/^exit.*/exit 0/' /sbin/initctl &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'force-unsafe-io' &amp;gt; /etc/dpkg/dpkg.cfg.d/docker-apt-speedup &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'DPkg::Post-Invoke { &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; };' &amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'APT::Update::Post-Invoke { &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;rm -f /var/cache/apt/archives/*.deb /var/cache/apt/archives/partial/*.deb /var/cache/apt/*.bin || true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; };' &amp;gt;&amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'Dir::Cache::pkgcache &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; Dir::Cache::srcpkgcache &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;' &amp;gt;&amp;gt; /etc/apt/apt.conf.d/docker-clean &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'Acquire::Languages &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;' &amp;gt; /etc/apt/apt.conf.d/docker-no-languages &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\t\t&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;amp;&amp;amp; echo 'Acquire::GzipIndexes &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; Acquire::CompressionTypes::Order:: &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gz&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;' &amp;gt; /etc/apt/apt.conf.d/docker-gzip-indexes&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2016-01-26T17:48:33.59869621Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c sed -i 's/^#&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;s*&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(deb.*universe&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1/g' /etc/apt/sources.list&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2016-01-26T17:48:34.465253028Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c #(nop) CMD [&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/bin/bash&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2018-11-01T03:19:16.4562755Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c #(nop) COPY file:8069dbb6bfc301562a8581e7bbe2b7675c2f96108903c0889d258cd1e11a12f6 in /app/ &quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;,
    &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;created&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;2018-11-01T03:19:16.8517953Z&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;created_by&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;/bin/sh -c #(nop)  CMD [&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/bin/sh&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;-c&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;python /app/app.py&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;]&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;empty_layer&quot;&lt;/span&gt;: &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;os&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;linux&quot;&lt;/span&gt;,
  &lt;span class=&quot;s2&quot;&gt;&quot;rootfs&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;: &lt;span class=&quot;s2&quot;&gt;&quot;layers&quot;&lt;/span&gt;,
    &lt;span class=&quot;s2&quot;&gt;&quot;diff_ids&quot;&lt;/span&gt;: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;sha256:3cbe18655eb617bf6a146dbd75a63f33c191bf8c7761bd6a8d68d53549af334b&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;sha256:84cc3d400b0d610447fbdea63436bad60fb8361493a32db380bd5c5a79f92ef4&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;sha256:ed58a6b8d8d6a4e2ecb4da7d1bf17ae8006dac65917c6a050109ef0a5d7199e6&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef&quot;&lt;/span&gt;,
      &lt;span class=&quot;s2&quot;&gt;&quot;sha256:9720cebfd814895bf5dc4c1c55d54146719e2aaa06a458fece786bf590cea9d4&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这是一个非常大的 JSON 文件，但通过这个文件你可以看到这里有很多不同的元数据。尤其重要的是，这关乎如何将此镜像转换为可以运行的容器的元数据（要运行的命令和要添加的环境变量）。&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;镜像如洋葱&quot;&gt;镜像如洋葱&lt;/h2&gt;

&lt;p&gt;镜像与洋葱都有很多层。但是什么是层？接下来我选取&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb&lt;/code&gt;一探究竟，因为这是『层』列表中的第一个。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls &lt;/span&gt;cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb
VERSION   json      layer.tar
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;又有一个压缩文件 (tarfile)，继续解压并打开看看。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;tree &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; 1
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── bin
├── boot
├── dev
├── etc
├── home
├── lib
├── lib64
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin
├── srv
├── sys
├── tmp
├── usr
└── var
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这就是 Docker 镜像的最大秘密，它由文件系统的不同视图组成！这一层有很多内容，用户空间二进制文件在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/bin&lt;/code&gt;, 共享函数库在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/lib&lt;/code&gt;，你可以在一个标准 Ubuntu 文件系统中看到的几乎一切内容。那么每个层究竟包含什么？通过它可以知道哪些层来自基本镜像，以及哪些层是由我们添加的。&lt;/p&gt;

&lt;p&gt;使用我们之前做的相同的过程，但在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ubuntu:15.04&lt;/code&gt;我可以看到这些层。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cac0b96b79417d5163fbd402369f74e3fe4ff8223b655e0b603a8b570bcc76eb
28441336175b9374d04ee75fdb974539e9b8cad8fec5bf0ff8cea6f8571d0114
4631663ba627c9724cd701eff98381cb500d2c09ec78a8c58213f3225877198e
c4f8838502da6456ebfcb3f755f8600d79552d1e30beea0ccc62c13a2556da9c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;这些都属于 ubuntu 基本镜像，也就是来自&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM ubuntu:15.04&lt;/code&gt;命令。由此我们预测&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_test_image&lt;/code&gt;图像的最顶层&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;6c91b695f2ed98362f511f2490c16dae0dcf8119bcfe2fe9af50305e2173f373&lt;/code&gt;应该来自命令&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COPY app.py / app /&lt;/code&gt;。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;tree
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
└── app
    └── app.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;果不其然，所有内容都是我们对文件系统所做的更改，仅仅添加了 app.py 文件。&lt;/p&gt;

&lt;h3 id=&quot;视图展示&quot;&gt;视图展示&lt;/h3&gt;

&lt;p&gt;从视觉上看，我们的图像是这样的。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/in-post/whats-in-a-docker-image/layers.png&quot; alt=&quot;layers&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;加分回合&quot;&gt;加分回合&lt;/h3&gt;

&lt;p&gt;手动完成这项工作需要付出相当大的时间，但至少这样做一次是有益的。如果您希望将来分析镜像，可以使用开源工具 &lt;a href=&quot;https://github.com/wagoodman/dive&quot;&gt;dive&lt;/a&gt;。
&lt;img src=&quot;/img/in-post/whats-in-a-docker-image/dive.png&quot; alt=&quot;dive&quot; /&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;容器是如何运行的&quot;&gt;容器是如何运行的&lt;/h2&gt;

&lt;p&gt;现在我们已经理解了一个 Docker 镜像是什么，那么 Docker 是如何把它变成一个运行中的容器呢？&lt;/p&gt;

&lt;h3 id=&quot;文件系统&quot;&gt;文件系统&lt;/h3&gt;

&lt;p&gt;每个容器都有它们自己的文件系统视图，Docker 获取镜像所有的层，并使它们层叠在一起，以呈现为文件系统的一个视图。这个技术称为 &lt;a href=&quot;https://en.wikipedia.org/wiki/Union_mount&quot;&gt;Union Mounting&lt;/a&gt;，Docker 支持 Linux 上的几个 Union Mount 文件系统，主要是 &lt;a href=&quot;https://en.wikipedia.org/wiki/OverlayFS&quot;&gt;OverlayFS&lt;/a&gt; 和 &lt;a href=&quot;https://en.wikipedia.org/wiki/Aufs&quot;&gt;AUFS&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;但是这并非全部，容器是短暂的，容器运行时对文件系统的更改不应该在容器停止时保存。一种方法是将整个镜像复制到其他地方，这样更改不会影响原始文件。这不是非常高效，替代方法（以及 Docker 所做的）是在容器中的文件系统的最顶部添加一个瘦读/写层，进行更改。如果您需要对下面某个层中的文件进行更改，则需要将该文件复制到进行更改的顶层。这称为 &lt;a href=&quot;https://en.wikipedia.org/wiki/Copy-on-write&quot;&gt;Copy-On-Write&lt;/a&gt;。当容器停止运行时，将丢弃最顶层的文件系统层。&lt;/p&gt;

&lt;p&gt;来自 &lt;a href=&quot;https://docs.docker.com/v17.09/engine/userguide/storagedriver/imagesandcontainers/#images-and-layers&quot;&gt;Docker 文档&lt;/a&gt; 的下图显示了最顶层。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/in-post/whats-in-a-docker-image/container-layers.jpg&quot; alt=&quot;container-layers&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;其他&quot;&gt;其他&lt;/h3&gt;

&lt;p&gt;启动容器的完整过程超出了本文的范围。在文件系统之后，镜像除了用于配置接下来的一些步骤的元数据之外，没有许多其他用途。完整而言，要创建一个正在运行的容器，我们需要使用命名空间 &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_namespaces&quot;&gt;Namespaces&lt;/a&gt;&lt;/em&gt; 来控制进程可以看到的内容（文件系统，进程，网络，用户等）；使用 &lt;em&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Cgroups&quot;&gt;cgroups&lt;/a&gt;&lt;/em&gt; 来控制进程可以使用的资源（内存，CPU，网络等）；安全功能来控制进程可以执行的操作（Capabilities, AppArmor, SELinux, Seccomp）。&lt;/p&gt;
</description>
        <pubDate>Tue, 29 Jan 2019 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2019/01/29/whats-in-a-docker-image/</link>
        <guid isPermaLink="true">https://yqsas.com/2019/01/29/whats-in-a-docker-image/</guid>
        
        <category>Docker</category>
        
        <category>译</category>
        
        
      </item>
    
      <item>
        <title>n2n-v2 局域网穿透指南</title>
        <description>&lt;p&gt;日前，由于项目需要一部分人驻场外地开发，于是项目组之前在同一局域网内开发的协作模式受到影响，导致 注册中心、网关等公共服务无法连接各业务服务端点。最直接的解决方式就是再造局域网环境，之前接触过花生壳，也了解 udp 打洞基本概念，于是想到可以两地远程连入一个自建局域网。&lt;/p&gt;

&lt;p&gt;经过一番了解，了解到相关实现工具选择不少，如&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n2n、softether、frp、ZeroTier&lt;/code&gt;等。&lt;/p&gt;

&lt;p&gt;鉴于 n2n 多平台、p2p 通信以及部署简单等特性，选择使用 n2n。最终实现效果是各地电脑 vpn 拨入指定 n2n 服务器，即可处于同一局域网，实现内网穿透效果。&lt;/p&gt;

&lt;h2 id=&quot;linux-安装&quot;&gt;Linux 安装&lt;/h2&gt;

&lt;h3 id=&quot;编译安装&quot;&gt;编译安装&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;环境&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; yum &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; openssl-devel
 yum &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; cmake
 yum &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; net-tools
 yum &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; gcc gcc-c++

 git clone https://github.com/meyerd/n2n.git

 &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;n2n/n2n_v2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;编译&lt;/p&gt;

    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nb&quot;&gt;mkdir &lt;/span&gt;build
 &lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;build
 cmake ..
 make &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; make &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;服务端启动supernode&quot;&gt;服务端启动（supernode）&lt;/h3&gt;

&lt;p&gt;服务端运行，需要开放对应 UDP 端口 7654&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;supernode &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; 7654
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;将服务端也作为客户端启动，加入到虚拟网络中。&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;edge &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; 192.168.10.11 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; group &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; password &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; server-ip:port
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;客户端启动edgenode&quot;&gt;客户端启动（edgenode）&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;edge &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; 192.168.10.21 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; group &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; password &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; server-ip:port
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;查看状态&quot;&gt;查看状态&lt;/h3&gt;

&lt;p&gt;查看 edge 或者 supernode 进程&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ps &lt;span class=&quot;nt&quot;&gt;-ef&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;supernode

ps &lt;span class=&quot;nt&quot;&gt;-ef&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;edge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;macos-安装&quot;&gt;macOS 安装&lt;/h2&gt;

&lt;p&gt;截止目前 Mojave 10.14.2 版本可用。&lt;/p&gt;

&lt;h3 id=&quot;安装-n2n&quot;&gt;安装 n2n&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;openssl
brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;cmake

git clone https://github.com/meyerd/n2n.git
&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;n2n/n2n_v2
&lt;span class=&quot;c&quot;&gt;#编辑 n2n_v2/CMakeLists.txt 文件，找到 set(CMAKE_C_FLAGS 和 set(CMAKE_CXX_FLAGS 两行，在这两行的里面括号里面的部分，加入编译参数：&lt;/span&gt;
vi CMakeLists.txt

&lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt;/usr/local/opt/openssl/include &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt;/usr/local/opt/openssl/lib

&lt;span class=&quot;c&quot;&gt;#在 n2n_v2 创建 build 文件夹，cmake .. 来创建 Makefile, 然后 make&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;make &lt;span class=&quot;nb&quot;&gt;install
sudo chmod&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; 777 /usr/local/sbin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;安装虚拟网卡&quot;&gt;安装虚拟网卡&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;brew cask &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;tuntap

&lt;span class=&quot;c&quot;&gt;#查看是否有如下两个内核扩展&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /Library/Extensions/tap.kext
&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; /Library/Extensions/tun.kext
&lt;span class=&quot;c&quot;&gt;#校验内核扩展的参数&lt;/span&gt;
find /Library/Extensions/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;tap,tun&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;.kext/ &lt;span class=&quot;nt&quot;&gt;-type&lt;/span&gt; f | xargs shasum
&lt;span class=&quot;c&quot;&gt;#加载内核扩展&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /sbin/kextload /Library/Extensions/tap.kext
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; /sbin/kextload /Library/Extensions/tun.kext
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;客户端启动&quot;&gt;客户端启动&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;edge &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; 192.168.10.31 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; group &lt;span class=&quot;nt&quot;&gt;-k&lt;/span&gt; password &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; server-ip:port
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;windows-安装&quot;&gt;Windows 安装&lt;/h2&gt;

&lt;h3 id=&quot;windows-版说明&quot;&gt;windows 版说明&lt;/h3&gt;

&lt;p&gt;n2n_v2 版本 windows 客户端需要自己编译，编译出来的 edge.exe 替换安装软件里的 edge2.exe 即可。&lt;/p&gt;

&lt;p&gt;以下提供个人编译出的客户端程序：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;windows 版 n2n: &lt;a href=&quot;https://pan.baidu.com/s/1M0rg0b0_uw2n9TkjFdaI3Q&quot;&gt;n2n-gui 安装包&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;最新 windows 版编译 (2018-12-30)：&lt;a href=&quot;https://pan.baidu.com/s/1SDMx7VcsOMDyaYtQlF8pqg&quot;&gt;edge2&lt;/a&gt;
    &lt;blockquote&gt;
      &lt;p&gt;编译环境 windows10-64 位，各位也可参考下文自行编译。&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;windows-版本编译&quot;&gt;windows 版本编译&lt;/h3&gt;

&lt;p&gt;参考：&lt;a href=&quot;http://gohom.win/2016/09/03/n2n-p2pnet/&quot;&gt;P2P 网络-n2n 穿墙-全平台&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;过程：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;安装 cmake&lt;/li&gt;
  &lt;li&gt;安装 Mingw&lt;/li&gt;
  &lt;li&gt;编译 exe 文件&lt;/li&gt;
  &lt;li&gt;重命名并替换软件安装中的 edg2.exe 文件&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;参考&quot;&gt;参考&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;ul&gt;
    &lt;li&gt;&lt;a href=&quot;http://gohom.win/2016/09/03/n2n-p2pnet/&quot;&gt;P2P 网络-n2n 穿墙-全平台&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://my.oschina.net/u/2366984/blog/1492433&quot;&gt;n2n 内网穿透打洞部署全过程&lt;/a&gt;&lt;/li&gt;
    &lt;li&gt;&lt;a href=&quot;https://www.5288z.com/2220.html&quot;&gt;Mac OS High Sierra 上编译 N2N 通过&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Sun, 30 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2018/12/30/n2n-v2-install/</link>
        <guid isPermaLink="true">https://yqsas.com/2018/12/30/n2n-v2-install/</guid>
        
        <category>n2n</category>
        
        <category>内网穿透</category>
        
        
      </item>
    
      <item>
        <title>Spring Security OAuth2 表单登录 refresh token 未生成问题</title>
        <description>&lt;p&gt;之前集成 OAuth2 后，一直用默认的登录路径/oauth/token，但是需要把客户端和客户端密钥明文传输，且登录成功后，后端后续处理不方便。于是打算使用自定义 formLogin 路径方式提供登录。&lt;/p&gt;

&lt;h2 id=&quot;过程&quot;&gt;过程&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;配置 AuthorizationServerConfig，使用 redisTokenStore 配置 DefaultTokenServices，使用 JdbcClientDetailsService 配置 ClientDetailsService。&lt;/li&gt;
  &lt;li&gt;新建 FormAuthenticationConfig，配置 HttpSecurity http 访问 formLogin 方法，并自定义登录路径 loginProcessingUrl 为/oauth/form，再自定义 successHandler 类（继承 SavedRequestAwareAuthenticationSuccessHandler），处理登录成功后手动生成 token 并返回给前端。&lt;/li&gt;
  &lt;li&gt;问题出现：使用 TokenServices.createAccessToken，手动创建出来的 token 无 refreshToken，而使用/oauth/token 端点则正常。&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;问题定位&quot;&gt;问题定位&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;追踪 TokenServices.createAccessToken 方法，发现其中生成 refresh_token 的方法，是通过判断 ClientDetail 里的认证方式是否包含 refresh_token 来确定：&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;isSupportRefreshToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;OAuth2Request&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;clientAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clientDetailsService&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nc&quot;&gt;ClientDetails&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clientDetailsService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;loadClientByClientId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;clientAuth&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getClientId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAuthorizedGrantTypes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;contains&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;refresh_token&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;supportRefreshToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;确认项目中 ClientDetail 中确实包含 refresh_token 后，再断点追踪，才知道 DefaultTokenServices 里面的 clientDetailsService 为空，导致无法获取客户端详情 clientDetails。&lt;/p&gt;

&lt;h2 id=&quot;解决方式&quot;&gt;解决方式&lt;/h2&gt;

&lt;p&gt;配置 DefaultTokenServices 时&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;设置 clientDetailsService&lt;/li&gt;
  &lt;li&gt;设置 supportRefreshToken 为 true（默认 false)，如此所有 token 都需要创建 refreshToken&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Bean&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Primary&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultTokenServices&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;DefaultTokenServices&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultTokenServices&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DefaultTokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;defaultTokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setTokenStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redisTokenStore&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//1&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;defaultTokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setClientDetailsService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clientDetails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//2&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;defaultTokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setSupportRefreshToken&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultTokenServices&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;1 和 2 都不可缺少，因为调用刷新 token 方法的时候，DefaultTokenServices 是直接取 supportRefreshToken 值判断，而非调用 isSupportRefreshToken 方法判断，而 supportRefreshToken 默认 false。这算是一个 bug 吧。&lt;/p&gt;

&lt;h2 id=&quot;总结&quot;&gt;总结&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;直接拿开源项目并不十分可靠，需要仔细理解细节；&lt;/li&gt;
  &lt;li&gt;有 BUG，看源码。&lt;/li&gt;
&lt;/ol&gt;
</description>
        <pubDate>Tue, 25 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://yqsas.com/2018/12/25/spring-security-formLogin-missing-refreshToken/</link>
        <guid isPermaLink="true">https://yqsas.com/2018/12/25/spring-security-formLogin-missing-refreshToken/</guid>
        
        <category>Spring</category>
        
        <category>Java</category>
        
        
      </item>
    
  </channel>
</rss>
