<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>字段映射 - tag - 沐木</title><link>https://oldletter.cn/tags/%E5%AD%97%E6%AE%B5%E6%98%A0%E5%B0%84/</link><description>字段映射 - tag - 沐木</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Thu, 23 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://oldletter.cn/tags/%E5%AD%97%E6%AE%B5%E6%98%A0%E5%B0%84/" rel="self" type="application/rss+xml"/><item><title>数据开放平台架构设计（四）：数据转换与加工</title><link>https://oldletter.cn/posts/dp-04-data-transform/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/dp-04-data-transform/</guid><description><![CDATA[<blockquote>
<p><strong>上一篇：</strong> <a href="/posts/dp-03-auth-and-control/" rel="">数据开放平台（三）：鉴权与访问控制</a></p></blockquote>
<p>SQL 查出来的原始数据，通常不能直接给调用方用。数据库字段名是 <code>user_name</code>，调用方要 <code>userName</code>；手机号 <code>13812345678</code> 不能直接暴露，得打成 <code>138****5678</code>；日期格式是 <code>2026-04-23 10:30:00</code>，调用方只要 <code>2026-04-23</code>。</p>
<p>这些&quot;末尾一公里&quot;的数据加工，就是数据转换引擎干的事。它不是替代数仓 ETL，也不应该把复杂计算都塞到接口层；它更适合做轻量、在线、和接口返回强相关的处理。</p>
<hr>
<h2 id="一整体设计">一、整体设计</h2>
<p>数据转换引擎用<strong>规则驱动</strong>的架构。用户在界面上配置转换规则，运行时引擎按规则依次处理。每条规则是一个独立的 Handler，可插拔、可组合。</p>
<p>数据转换流水线要把字段形态写清楚，避免后续在响应层临时拼逻辑：</p>
<div class="mermaid" id="id-2" data-mermaid-definition="Zmxvd2NoYXJ0IExSCiAgICAgICAgICAgICAgICAgICAgQVsi5Y6f5aeL57uT5p6c6ZuGPGJyLz5kYl9jb2x1bW4iXSAtLT4gQlsi5a2X5q615pig5bCEPGJyLz5hcGlGaWVsZCJdCiAgICAgICAgICAgICAgICAgICAgQiAtLT4gQ1si6ISx5pWPPGJyLz5tYXNrZWRGaWVsZCJdCiAgICAgICAgICAgICAgICAgICAgQyAtLT4gRFsi5qC85byP5YyWPGJyLz5kaXNwbGF5VmFsdWUiXQogICAgICAgICAgICAgICAgICAgIEQgLS0&#43;IEVbIuWtl&#43;auteiuoeeulzxici8&#43;Y29tcHV0ZWRGaWVsZCJdCiAgICAgICAgICAgICAgICAgICAgRSAtLT4gRlsi5bCP57uT5p6c6ZuG6IGa5ZCIPGJyLz5zdW1tYXJ5Il0KICAgICAgICAgICAgICAgICAgICBGIC0tPiBHWyLlrZfmrrXmnYPpmZDov4fmu6Q8YnIvPnZpc2libGVGaWVsZHMiXQogICAgICAgICAgICAgICAgICAgIEcgLS0&#43;IEhbIuWTjeW6lOWMheijhTxici8&#43;ZGF0YeOAgW1ldGHjgIF0cmFjZUlkIl0=">flowchart LR
                    A[&#34;原始结果集&lt;br/&gt;db_column&#34;] --&gt; B[&#34;字段映射&lt;br/&gt;apiField&#34;]
                    B --&gt; C[&#34;脱敏&lt;br/&gt;maskedField&#34;]
                    C --&gt; D[&#34;格式化&lt;br/&gt;displayValue&#34;]
                    D --&gt; E[&#34;字段计算&lt;br/&gt;computedField&#34;]
                    E --&gt; F[&#34;小结果集聚合&lt;br/&gt;summary&#34;]
                    F --&gt; G[&#34;字段权限过滤&lt;br/&gt;visibleFields&#34;]
                    G --&gt; H[&#34;响应包装&lt;br/&gt;data、meta、traceId&#34;]</div><div class="code-block code-line-numbers open" style="counter-reset: code-block 0">
    <div class="code-header language-java">
        <span class="code-title"><i class="arrow fas fa-angle-right" aria-hidden="true"></i></span>
        <span class="ellipses"><i class="fas fa-ellipsis-h" aria-hidden="true"></i></span>
        <span class="copy" title=""><i class="far fa-copy" aria-hidden="true"></i></span>
    </div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-java" data-lang="java"><span class="line"><span class="cl"><span class="nd">@Component</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">DataTransformEngine</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="c1">// 所有 TransformHandler 按 Order 排序</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nd">@Autowired</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">private</span><span class="w"> </span><span class="n">List</span><span class="o">&lt;</span><span class="n">TransformHandler</span><span class="o">&gt;</span><span class="w"> </span><span class="n">handlers</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="kd">public</span><span class="w"> </span><span class="n">List</span><span class="o">&lt;</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="nf">transform</span><span class="p">(</span><span class="n">TransformConfig</span><span class="w"> </span><span class="n">config</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                                                 </span><span class="n">List</span><span class="o">&lt;</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">rawData</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">config</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="kc">null</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="n">config</span><span class="p">.</span><span class="na">isEmpty</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="n">rawData</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="n">List</span><span class="o">&lt;</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="o">&gt;&gt;</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">(</span><span class="n">rawData</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">TransformHandler</span><span class="w"> </span><span class="n">handler</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">handlers</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">handler</span><span class="p">.</span><span class="na">supports</span><span class="p">(</span><span class="n">config</span><span class="p">))</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">                </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">handler</span><span class="p">.</span><span class="na">apply</span><span class="p">(</span><span class="n">config</span><span class="p">,</span><span class="w"> </span><span class="n">result</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">            </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="n">result</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span></span></span></code></pre></div></div>
<p>生产里我会给转换引擎加两个边界：第一，单次处理行数不能无限大，超过阈值必须分页或异步导出；第二，规则执行要记录耗时，某条自定义正则特别慢时能快速定位。</p>]]></description></item></channel></rss>