接口 https://www.e-learn.cn/tag/jiekou zh-hans C# 面试常见问题 https://www.e-learn.cn/topic/4113833 <span>C# 面试常见问题</span> <span><span lang="" about="/user/8" typeof="schema:Person" property="schema:name" datatype="">寵の児</span></span> <span>2021-02-18 18:32:01</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <pre class="answer-text mb-10"><code>Q:接口与抽象类的区别(所有公司都问,关键是我基本上都说不全,翻了个最简单好记的答案共享)</code></pre> <pre class="answer-text mb-10"><code>按三点答:先答属性:抽象类可以有普通成员变量,接口不行; 然后答方法:抽象类有非抽象的方法和构造方法,并且修饰符可以是私有的,接口只能是抽象的方法,并且修饰符是public,最后说一句只能继承一个抽象类,但能实现多个接口。</code></pre> <pre class="answer-text mb-10"><code>Q:ADO.NET的特点,几个对象都是用来干啥的</code></pre> <pre class="answer-text mb-10"><code>Q:asp.net页面传值有哪些方式</code></pre> <pre class="answer-text mb-10"><code>Q:转发和重定向有什么不同</code></pre> <pre class="answer-text mb-10"><code>Q:IIS6和IIS7是怎么工作的?他们有什么不同</code></pre> <pre class="answer-text mb-10"><code>Q: 存储过程有什么优势 A: 存储过程是放在数据库服务器上的,最直观的就是在执行sql的时候不需要网络传输sql语句只要传输 需要执行的数据就好.存储过程是预编译的普通sql执行需到数据库中进行检查sql是否正确然后再进行编译,执行效率比普通sql高。</code></pre> <pre class="answer-text mb-10"><code>Q:union union all的区别 A: union 把两个表之间的数据放到一起并进行排序,去重复.union all 把两个表的数据放到一起不排序不去重。</code></pre> <pre class="answer-text mb-10"><code>Q:数据库删除数据有哪些方法?使用哪些命令,都有哪些效果? A:可以通过DROP TRUNCATE 以及DELETE进行数据的删除,DROP 可以删除数据库和表(整个结构),TRUNCATE在不带条件时与DELETE类似<span></span> 二者均删除表中的全部行。但 TRUNCATE TABLE 比 DELETE 速度快,且使用的系统和事务日志资源少。   DELETE 语句每次删除一行,并在事务日志中为所删除的每行记录一项。 TRUNCATE TABLE 通过释放存储表数据所用的数据页来删除数据,并且只在事务日志中记录页的释放。  以上回答摘抄与百度知道 我个人的理解TRUNCATE 删除表的所有数据,速度比DELETE快 不能跟WHERE子句,ORDER BY 删除数据返回结果是0不记录日志, DELETE 不带条件删除表所有数据,速度没有TRUNCATE快,可以跟WHERE子句,可以被ROWBACK,并记录日志,返回删除的条数。</code></pre> <pre class="answer-text mb-10"><code><span></span></code></pre> <pre class="answer-text mb-10"><code><span></span></code></pre> <pre class="answer-text mb-10"><code>面试前请记得翻答案哈哈哈</code></pre> <span></span> <p> <br /></p> <div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/170703/blog/143009</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/c" hreflang="zh-hans">c#</a></div> <div class="field--item"><a href="/tag/mianshi" hreflang="zh-hans">面试</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> <div class="field--item"><a href="/tag/chouxianglei" hreflang="zh-hans">抽象类</a></div> </div> </div> Thu, 18 Feb 2021 10:32:01 +0000 寵の児 4113833 at https://www.e-learn.cn (Interface)接口特点 https://www.e-learn.cn/topic/3555808 <span>(Interface)接口特点</span> <span><span lang="" about="/user/144" typeof="schema:Person" property="schema:name" datatype="">核能气质少年</span></span> <span>2020-04-08 07:04:17</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p>接口是一种规范。只要一个类继承了一个接口,这个类就必须实现这个接口中所有的成员</p> <p>为了多态。 接口不能被实例化。<br />也就是说,接口不能new(不能创建对象)</p> <p><br /> 接口中的成员不能加“访问修饰符”,接口中的成员访问修饰符为public,不能修改。</p> <p><br />(默认为public) 接口中的成员不能有任何实现(“光说不做”,只是定义了一组未实现的成员)。</p> <p><br /> 接口中只能有方法、属性、索引器、事件,不能有“字段”和构造函数。</p> <p>接口与接口之间可以继承,并且可以多继承。</p> <p>接口并不能去继承一个类,而类可以继承接口 (接口只能继承于接口,而类既可以继承接口,也可以继承类)</p> <p> 实现接口的子类必须实现该接口的全部成员。</p> <p> 一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并实现了接口IA,那么语法上A必须写在IA的前面。</p> <p><br />class MyClass:A,IA{},因为类是单继承的。</p> <p><br />显示实现接口的目的:解决方法的重名问题<br />什么时候显示的去实现接口:<br />当继承的借口中的方法和参数一摸一样的时候,要是用显示的实现接口</p> <p><br /> 当一个抽象类实现接口的时候,需要子类去实现接口。</p> <p> </p> <div class="alert alert-success" role="alert"><p>来源:<code>https://www.cnblogs.com/mhg215/p/6087425.html</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 23:04:17 +0000 核能气质少年 3555808 at https://www.e-learn.cn TMS320DM8168浮点DSP C674x + ARM Cortex-A8开发板SATA接口、USB接口 https://www.e-learn.cn/topic/3554511 <span>TMS320DM8168浮点DSP C674x + ARM Cortex-A8开发板SATA接口、USB接口</span> <span><span lang="" about="/user/86" typeof="schema:Person" property="schema:name" datatype="">谁说我不能喝</span></span> <span>2020-04-07 17:18:19</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>CPU</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span><span style="background-color:#ffffff"><span>TI</span></span></span> <span><span style="background-color:#ffffff"><span>TMS320DM8168</span></span></span><span><span style="background-color:#ffffff"><span>是</span></span></span><span><span style="background-color:#ffffff"><span>一款</span></span></span><span><span style="background-color:#ffffff"><span>高性能</span></span></span><span><span style="background-color:#ffffff"><span>嵌入式</span></span></span><span><span style="background-color:#ffffff"><span>32位工业级</span></span></span><span><span style="background-color:#ffffff"><span>ARM Cortex-A8</span></span></span> <span><span style="background-color:#ffffff"><span>+</span></span></span> <span><span style="background-color:#ffffff"><span>DSP C674x</span></span></span><span><span style="background-color:#ffffff"><span>处理器。</span></span></span><span><span style="background-color:#ffffff"><span>拥有多种工业接口资源,</span></span></span><span><span style="background-color:#ffffff"><span>以下是</span></span></span><span><span style="background-color:#ffffff"><span>DM8168</span></span></span><span><span style="background-color:#ffffff"><span> CPU资源框图:</span></span></span></span></span></span></span></span></p> <p><img height="369" width="511" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-117228c25acf421e84292b595e353be0379.png" data-original="https://oscimg.oschina.net/oscnet/up-117228c25acf421e84292b595e353be0379.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>SATA</strong></span></span></span></strong><strong><span><span style="background-color:#ffffff"><span><strong>接口</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>开发板引出了2个</span></span></span><span><span style="background-color:#ffffff"><span>7pin SATA</span></span></span><span><span style="background-color:#ffffff"><span>盘接口SATA0、SATA1,</span></span></span><span><span style="background-color:#ffffff"><span>接口</span></span></span><span><span style="background-color:#ffffff"><span>为J1、J</span></span></span><span><span style="background-color:#ffffff"><span>8</span></span></span><span><span style="background-color:#ffffff"><span>,</span></span></span><span><span style="background-color:#ffffff"><span>硬件及引脚如图:</span></span></span></span></span></span></span></p> <p><img height="126" width="227" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-15b0ea4f32a270ee2a5c2c33a05070e7ead.png" data-original="https://oscimg.oschina.net/oscnet/up-15b0ea4f32a270ee2a5c2c33a05070e7ead.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="123" width="613" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-cb35146bd4681cf29f432dd75fee00771c1.png" data-original="https://oscimg.oschina.net/oscnet/up-cb35146bd4681cf29f432dd75fee00771c1.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>USB</strong></span></span></span></strong><strong><span><span style="background-color:#ffffff"><span><strong>接口</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>CON8</span></span></span><span><span style="background-color:#ffffff"><span>、CON</span></span></span><span><span style="background-color:#ffffff"><span>12</span></span></span><span><span style="background-color:#ffffff"><span>、C</span></span></span><span><span style="background-color:#ffffff"><span>ON13</span></span></span><span><span style="background-color:#ffffff"><span>均为</span></span></span><span><span style="background-color:#ffffff"><span>USB</span></span></span><span><span style="background-color:#ffffff"><span> 2.0</span></span></span><span><span style="background-color:#ffffff"><span>接口</span></span></span><span><span style="background-color:#ffffff"><span>。CON12、C</span></span></span><span><span style="background-color:#ffffff"><span>ON13</span></span></span><span><span style="background-color:#ffffff"><span>物理接口为2个双层A型母座USB HOST口,</span></span></span><span><span style="background-color:#ffffff"><span>可以接USB摄像头、USB键盘、USB鼠标、U盘等常见的USB外设。CON</span></span></span><span><span style="background-color:#ffffff"><span>8物理接口为</span></span></span><span><span style="background-color:#ffffff"><span>Micro</span></span></span> <span><span style="background-color:#ffffff"><span>B型母座</span></span></span><span><span style="background-color:#ffffff"><span>,配置为USB HOST后</span></span></span><span><span style="background-color:#ffffff"><span>它</span></span></span><span><span style="background-color:#ffffff"><span>可以通过OTG转接头转成A型母座</span></span></span><span><span style="background-color:#ffffff"><span>。对应引脚定义如下图:</span></span></span></span></span></span></span></p> <p><img height="129" width="201" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-bab4d2484b72f3552d64ca7a84b3435043e.png" data-original="https://oscimg.oschina.net/oscnet/up-bab4d2484b72f3552d64ca7a84b3435043e.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="98" width="152" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-97f67ce3c1319c8822569673c946f62847e.png" data-original="https://oscimg.oschina.net/oscnet/up-97f67ce3c1319c8822569673c946f62847e.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="309" width="604" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-e7a93efbcb70e6d7efe1d2c7202f683b750.png" data-original="https://oscimg.oschina.net/oscnet/up-e7a93efbcb70e6d7efe1d2c7202f683b750.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="144" width="454" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-4dd3be54fddda93ba0a453ddd087b5b489b.png" data-original="https://oscimg.oschina.net/oscnet/up-4dd3be54fddda93ba0a453ddd087b5b489b.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/4169033/blog/3223291</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/fudian" hreflang="zh-hans">浮点</a></div> <div class="field--item"><a href="/tag/usbjiekou" hreflang="zh-hans">usb接口</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 09:18:19 +0000 谁说我不能喝 3554511 at https://www.e-learn.cn python:接口请求中出现requests.exceptions.SSLError 和 InsecureRequestWarning的解决办法 https://www.e-learn.cn/topic/3554324 <span>python:接口请求中出现requests.exceptions.SSLError 和 InsecureRequestWarning的解决办法</span> <span><span lang="" about="/user/38" typeof="schema:Person" property="schema:name" datatype="">|▌冷眼眸甩不掉的悲伤</span></span> <span>2020-04-07 15:41:04</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p>1、在请求中加入verify=False,关闭认证---------解决requests.exceptions.SSLError</p> <p><img alt="" class="b-lazy" data-src="https://img2020.cnblogs.com/blog/1733308/202004/1733308-20200407150644140-1193297194.png" data-original="https://img2020.cnblogs.com/blog/1733308/202004/1733308-20200407150644140-1193297194.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p> </p> <p> </p> <p> 2、添加代码----------- 解决InsecureRequestWarning</p> <div> <pre>import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) </pre> </div> <p>  </p> <div class="alert alert-success" role="alert"><p>来源:<code>https://www.cnblogs.com/erchun/p/12653525.html</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 07:41:04 +0000 |▌冷眼眸甩不掉的悲伤 3554324 at https://www.e-learn.cn 防火墙双击热备 https://www.e-learn.cn/topic/3554209 <span>防火墙双击热备</span> <span><span lang="" about="/user/23" typeof="schema:Person" property="schema:name" datatype="">≯℡__Kan透↙</span></span> <span>2020-04-07 14:56:20</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p><img alt="" class="b-lazy" data-src="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830205002239-2142910026.png" data-original="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830205002239-2142910026.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p>配置FW_A各接口的IP地址(记得开管理功能 service-manage enable)</p> <p>interface GigabitEthernet1/0/0<br /> ip address 10.2.0.1 255.255.255.0</p> <p>service-manage enable</p> <p>service-manage all permit </p> <p>interface GigabitEthernet1/0/5<br /> ip address 10.3.0.1 255.255.255.0</p> <p>service-manage enable</p> <p>service-manage all permit </p> <p><br />#<br />interface GigabitEthernet1/0/6<br /> ip address 10.10.0.1 255.255.255.0</p> <p>service-manage enable</p> <p>service-manage all permit </p> <p><br />配置FW_B各接口的IP地址(记得开管理功能 service-manage enable)</p> <p align="left">interface GigabitEthernet1/0/0</p> <p align="left"> undo shutdown</p> <p align="left"> ip address 10.2.0.2 255.255.255.0</p> <p align="left">interface GigabitEthernet1/0/5</p> <p align="left"> undo shutdown</p> <p align="left"> ip address 10.3.0.2 255.255.255.0</p> <p align="left">interface GigabitEthernet1/0/6</p> <p align="left"> undo shutdown</p> <p align="left"> ip address 10.10.0.2 255.255.255.0</p> <p><br />将FW_A各接口加入相应的安全区域</p> <p>firewall zone trust<br /> set priority 85<br /> add interface GigabitEthernet0/0/0<br /> add interface GigabitEthernet1/0/0<br />#<br />firewall zone untrust<br /> set priority 5<br /> add interface GigabitEthernet1/0/5<br />#<br />firewall zone dmz<br /> set priority 50<br /> add interface GigabitEthernet1/0/6</p> <p>将FW_B各接口加入相应的安全区域(同FW_A一样)</p> <p>在FW_A上配置一条缺省路由</p> <p>ip route-static 0.0.0.0 0.0.0.0 10.2.0.10<br />在FW_B上配置一条缺省路由(同FW_A一样)</p> <p>在FW_A上行业务接口GE1/0/0上配置VRRP备份组1,并设置其状态为Active</p> <p>interface GigabitEthernet1/0/0<br /> vrrp vrid 1 virtual-ip 10.2.0.100 active</p> <p>在FW_A下行业务接口GE1/0/5上配置VRRP备份组2,并设置其状态为Active</p> <p>interface GigabitEthernet1/0/5<br />vrrp vrid 2 virtual-ip 10.3.0.100 active<br />在FW_B上行业务接口GE1/0/0上配置VRRP备份组1,并设置其状态为Standby</p> <p align="left">interface GigabitEthernet1/0/0</p> <p align="left">vrrp vrid 1 virtual-ip 10.2.0.100 standby</p> <p>在FW_B下行业务接口GE1/0/5上配置VRRP备份组2,并设置其状态为Standby</p> <p align="left">interface GigabitEthernet1/0/5</p> <p align="left">vrrp vrid 2 virtual-ip 10.3.0.100 standby</p> <p>在FW_A上指定心跳口并启用双机热备功能。</p> <p> hrp enable<br /> hrp interface GigabitEthernet1/0/6 remote 10.10.0.2(对端防火墙接口地址)</p> <p><img alt="" class="b-lazy" data-src="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210624738-1733993937.png" data-original="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210624738-1733993937.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p>在FW_B上指定心跳口并启用双机热备功能。</p> <p align="left">[FW_B]hrp int g1/0/6 remote 10.10.0.1</p> <p align="left">[FW_A]hrp enable</p> <p><img alt="" class="b-lazy" data-src="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210649888-240363802.png" data-original="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210649888-240363802.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p> </p> <p>给R1配地址做静态</p> <p>interface GigabitEthernet0/0/0<br /> ip address 1.1.1.1 255.255.255.0</p> <p>ip route-static 10.2.0.0 255.255.255.0 1.1.1.10</p> <p>在LSW1配置vlan</p> <p>interface Vlanif10<br /> ip address 10.2.0.10 255.255.255.0<br />#<br />interface Vlanif100<br /> ip address 1.1.1.10 255.255.255.0</p> <p>interface GigabitEthernet0/0/1<br /> port link-type access<br /> port default vlan 10<br />#<br />interface GigabitEthernet0/0/2<br /> port link-type access<br /> port default vlan 10<br />#<br />interface GigabitEthernet0/0/3<br /> port link-type access<br /> port default vlan 100</p> <p> </p> <p>在LSW2配置trunk口(所有接口)</p> <p>interface GigabitEthernet0/0/1<br /> port link-type trunk<br /> port trunk allow-pass vlan 2 to 4094<br />#<br />interface GigabitEthernet0/0/2<br /> port link-type trunk<br /> port trunk allow-pass vlan 2 to 4094<br />#<br />interface GigabitEthernet0/0/3<br /> port link-type trunk<br /> port trunk allow-pass vlan 2 to 4094<br />#<br />interface GigabitEthernet0/0/4<br /> port link-type trunk<br /> port trunk allow-pass vlan 2 to 4094</p> <p><br />在FW_A上配置安全策略。双机热备状态成功建立后,FW_A的安全策略配置会自动备份到FW_B上<br />配置安全策略,允许内网用户访问Internet</p> <p align="left">FW_A</p> <p align="left">HRP_M[FW_A]security-policy (+B)</p> <p align="left">HRP_M[FW_A-policy-security]rule name permit_trust_untrust (+B)</p> <p align="left">HRP_M[FW_A-policy-security-rule-permit_trust_untrust]source-zone untrust  (+B)</p> <p align="left">HRP_M[FW_A-policy-security-rule-permit_trust_untrust]destination-zone trust  (+B)</p> <p align="left">HRP_M[FW_A-policy-security-rule-permit_trust_untrust]action permit  (+B)</p> <p align="left">FW_B</p> <p align="left">在B上备份设备已经进不去安全策略模式了</p> <p align="left"><img alt="" class="b-lazy" data-src="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210835729-1012488523.png" data-original="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210835729-1012488523.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p align="left">Dis cur查看(可以看到刚才创建的策略已经同步了)</p> <p align="left">rule name permit_trust_untrust</p> <p align="left">  source-zone untrust</p> <p align="left">  destination-zone trust</p> <p align="left">  action permit</p> <p>在FW_A上配置NAT策略。双机热备状态成功建立后,FW_A的NAT策略配置会自动备份到FW_B上</p> <p>nat-policy<br /> rule name AB<br /> source-zone untrust<br /> destination-zone trust<br /> action source-nat easy-ip</p> <p><img alt="" class="b-lazy" data-src="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210925445-365067228.png" data-original="https://img2018.cnblogs.com/blog/1670758/201908/1670758-20190830210925445-365067228.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p> </p> <div class="alert alert-success" role="alert"><p>来源:<code>https://www.cnblogs.com/TiAmoLJ/p/11437176.html</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/fanghuoqiang" hreflang="zh-hans">防火墙</a></div> <div class="field--item"><a href="/tag/trunk" hreflang="zh-hans">trunk</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 06:56:20 +0000 ≯℡__Kan透↙ 3554209 at https://www.e-learn.cn 创龙TMS320DM8168浮点DSP C674x + ARM Cortex-A8SATA接口、USB接口 https://www.e-learn.cn/topic/3554185 <span>创龙TMS320DM8168浮点DSP C674x + ARM Cortex-A8SATA接口、USB接口</span> <span><span lang="" about="/user/215" typeof="schema:Person" property="schema:name" datatype="">我的梦境</span></span> <span>2020-04-07 14:47:35</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>CPU</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>TI</span></span></span> <span><span style="background-color:#ffffff"><span>TMS320DM8168</span></span></span><span><span style="background-color:#ffffff"><span>是</span></span></span><span><span style="background-color:#ffffff"><span>一款</span></span></span><span><span style="background-color:#ffffff"><span>高性能</span></span></span><span><span style="background-color:#ffffff"><span>嵌入式</span></span></span><span><span style="background-color:#ffffff"><span>32位工业级</span></span></span><span><span style="background-color:#ffffff"><span>ARM Cortex-A8</span></span></span> <span><span style="background-color:#ffffff"><span>+</span></span></span> <span><span style="background-color:#ffffff"><span>DSP C674x</span></span></span><span><span style="background-color:#ffffff"><span>处理器。</span></span></span><span><span style="background-color:#ffffff"><span>拥有多种工业接口资源,</span></span></span><span><span style="background-color:#ffffff"><span>以下是</span></span></span><span><span style="background-color:#ffffff"><span>DM8168</span></span></span><span><span style="background-color:#ffffff"><span> CPU资源框图:</span></span></span></span></span></span></span></p> <p><img height="369" width="511" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-18b63f01e4c1ec98c3dd5fb78d29ccb3dd4.png" data-original="https://oscimg.oschina.net/oscnet/up-18b63f01e4c1ec98c3dd5fb78d29ccb3dd4.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="369" width="511" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-caacec91b34e312a68627909255ad8e7d43.png" data-original="https://oscimg.oschina.net/oscnet/up-caacec91b34e312a68627909255ad8e7d43.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>SATA</strong></span></span></span></strong><strong><span><span style="background-color:#ffffff"><span><strong>接口</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>开发板引出了2个</span></span></span><span><span style="background-color:#ffffff"><span>7pin SATA</span></span></span><span><span style="background-color:#ffffff"><span>盘接口SATA0、SATA1,</span></span></span><span><span style="background-color:#ffffff"><span>接口</span></span></span><span><span style="background-color:#ffffff"><span>为J1、J2,</span></span></span><span><span style="background-color:#ffffff"><span>硬件及引脚如图:</span></span></span></span></span></span></span></p> <p><img height="87" width="303" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-7ee3408ff66adde9479b0630d1078c35bfa.png" data-original="https://oscimg.oschina.net/oscnet/up-7ee3408ff66adde9479b0630d1078c35bfa.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="99" width="613" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-56eef4a1d654458af7792e06766e42004bc.png" data-original="https://oscimg.oschina.net/oscnet/up-56eef4a1d654458af7792e06766e42004bc.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><span><span style="background-color:#ffffff"><span><span><strong><strong><span><span style="background-color:#ffffff"><span><strong>USB</strong></span></span></span></strong><strong><span><span style="background-color:#ffffff"><span><strong>接口</strong></span></span></span></strong></strong></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>CON</span></span></span><span><span style="background-color:#ffffff"><span>9、CON8均为</span></span></span><span><span style="background-color:#ffffff"><span>USB</span></span></span><span><span style="background-color:#ffffff"><span> 2.0</span></span></span><span><span style="background-color:#ffffff"><span>接口,应用于各种不同的移动设备间的</span></span></span><span><span style="background-color:#ffffff"><span>连</span></span></span><span><span style="background-color:#ffffff"><span>接,进行数据交换</span></span></span><span><span style="background-color:#ffffff"><span>,传输</span></span></span><span><span style="background-color:#ffffff"><span>速度高达480Mbps</span></span></span><span><span style="background-color:#ffffff"><span>。CON9为A型母座USB HOST口,</span></span></span><span><span style="background-color:#ffffff"><span>可以接USB摄像头、USB键盘、USB鼠标、U盘等常见的USB外设。</span></span></span></span></span></span></span></p> <p><span><span style="background-color:#ffffff"><span><span><span><span style="background-color:#ffffff"><span>CON</span></span></span><span><span style="background-color:#ffffff"><span>8为</span></span></span><span><span style="background-color:#ffffff"><span>Micro</span></span></span> <span><span style="background-color:#ffffff"><span>B型母座</span></span></span><span><span style="background-color:#ffffff"><span>USB DRD口,它不能根据</span></span></span><span><span style="background-color:#ffffff"><span>设备情况自动切换为</span></span></span><span><span style="background-color:#ffffff"><span>HOST/DEVICE模式,</span></span></span><span><span style="background-color:#ffffff"><span>需要手动</span></span></span><span><span style="background-color:#ffffff"><span>进行</span></span></span><span><span style="background-color:#ffffff"><span>软件配置</span></span></span><span><span style="background-color:#ffffff"><span>,若配置为DEVICE模式它可直接使用Micro</span></span></span><span><span style="background-color:#ffffff"><span> USB线与</span></span></span><span><span style="background-color:#ffffff"><span>PC连接,若配置为HOST模式</span></span></span><span><span style="background-color:#ffffff"><span>它</span></span></span><span><span style="background-color:#ffffff"><span>可通过OTG转接头转成A型母座</span></span></span><span><span style="background-color:#ffffff"><span>。对应引脚定义如下图:</span></span></span></span></span></span></span></p> <p><img height="172" width="303" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-e357a4ffd3e4a9d807d19f507500b54da68.png" data-original="https://oscimg.oschina.net/oscnet/up-e357a4ffd3e4a9d807d19f507500b54da68.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="111" width="189" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-8b609d0bf0d3898bf4b34dcb02170487754.png" data-original="https://oscimg.oschina.net/oscnet/up-8b609d0bf0d3898bf4b34dcb02170487754.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p><img height="310" width="539" class="b-lazy" data-src="https://oscimg.oschina.net/oscnet/up-f8638987bf8ec6c0ee1ef5639aafe219650.png" data-original="https://oscimg.oschina.net/oscnet/up-f8638987bf8ec6c0ee1ef5639aafe219650.png" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <p> </p> <div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/4169033/blog/3223103</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/fudian" hreflang="zh-hans">浮点</a></div> <div class="field--item"><a href="/tag/usbjiekou" hreflang="zh-hans">usb接口</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 06:47:35 +0000 我的梦境 3554185 at https://www.e-learn.cn 接口interface https://www.e-learn.cn/topic/3553555 <span>接口interface</span> <span><span lang="" about="/user/53" typeof="schema:Person" property="schema:name" datatype="">依然范特西╮</span></span> <span>2020-04-07 11:54:35</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <h2 id="section">对象类型接口</h2> <h4 id="section-1">定义接口</h4> <pre>interface List { id: number; name: string; } interface Result { data: List[] } function render(result: Result) { result.data.forEach((value) =&gt; { console.log(value.id, value.name) }) } let result = { data: [ {id: 1, name: 'A'}, {id: 2, name: 'B'} ] } render(result) // 1 "A" // 2 "B" PS:   后端有时候会传来约定之外的字段,ts并不报错。所以只要传入的对象是必要条件就是被允许的:     let result = {   data: [   {id: 1, name: 'A', sex: 'male'},   {id: 2, name: 'B'}   ]   }   但是我们直接传入对象字面量,ts就会对额外的字段进行类型检查:    render({   data: [   {id: 1, name: 'A', sex: 'male'}, // 提示错误   {id: 2, name: 'B'}   ]   })  </pre> <h4 id="section-2">绕过类型检查的方法</h4> <p><strong>第一种方式: 将对象赋值给一个变量</strong> <strong>第二种方式是类型断言:as + 对象的类型,明确告诉编译器,对象的类型就是Result,编译器就会绕过类型检查</strong></p> <pre>render({ data: [ {id: 1, name: 'A', sex: 'male'}, // 提示错误 {id: 2, name: 'B'} ] } as Result) PS:   类型断言的另一种不建议用的方法,就是在对象前面加上&lt;Result&gt;,但是在React种容易产生歧义。 </pre> <p><strong>第三种方法是使用字符串索引签名</strong>,格式如下:</p> <pre>interface List{ id:number; name:string; [x,string]:any; } PS: 该签名的含义是用任意的字符串去索引List,会得到任意的结果,这样List就支持多个属性了。 </pre> <h4 id="section-3">可选属性(属性+格式)</h4> <p>假设有个新需求,需要判断value中是否有个新字段,如果有,就把它打印出来:</p> <pre>interface List { id: number; name: string; age?: number; } interface Result { data: List[] } function render(result: Result) { result.data.forEach((value) =&gt; { console.log(value.id, value.name) if(value.age) { console.log(value.age) } }) } let result = { data: [ {id: 1, name: 'A', sex: 'male'}, {id: 2, name: 'B'} ] } render(result) PS: 在render函数中进行判断,会提示错误,这时我们在List中添加属性age,result会报错,这就需要我们使用可选属性了。 </pre> <h4 id="readonly">只读属性(readonly + 属性格式)</h4> <p><strong>只读属性不允许修改</strong></p> <pre>interface List { readonly id: number; } function render(result: Result) { result.data.forEach((value) =&gt; { value.id ++ // 提示错误 }) } </pre> <h4 id="section-4">可索引类型的接口</h4> <p>以上属性的个数是固定的,当我们不确定属性个数时,就要用到可索引类型的接口,常用的有两种: <strong>用数字索引的接口</strong></p> <pre>interface StringArray { [index: number]: string } PS: 含义是用任意的数字去索引StringArray,会得到一个string,这就相当于声明了一个字符串类型的数组。 比如:     let chars: StringArray = ['A', 'B'] </pre> <p><strong>用字符串索引的接口</strong></p> <pre>interface Names { [x: string]: string } PS: 含义是用任意的字符串索引Names,得到的结果都是string,这样我们就不能并列声明number类型的成员了:     interface Names {   [x: string]: string   y: number // 提示错误   z: string   } </pre> <p>这两种索引签名是可以混用的</p> <pre>interface Names { [x: string]: string [z: number]: string } PS: 需要注意的是,数字索引签名的返回值一定要是字符串索引签名返回值的子类型,这是因为js会进行类型转换,将number转成string,这样就能保证类型的兼容性。 比如下面这样就会报错:     interface Names {   [x: string]: string   [z: number]: number // 提示错误   } 但这样就可以:     interface Names {   [x: string]: any   [z: number]: number   } </pre> <h2 id="section-5">函数类型接口</h2> <h4 id="section-6">定义接口</h4> <p><strong>用变量定义函数类型</strong></p> <pre>let add: (x: number, y: number) =&gt; number </pre> <p><strong>用接口定义函数类型</strong></p> <pre>interface Add { (x: number, y: number): number } </pre> <p><strong>用类型别名定义函数类型</strong></p> <pre>type Add = (x: number, y: number) =&gt; number let add: Add = (a, b) =&gt; a + b </pre> <p><strong>混合类型的接口</strong> 这种接口既可以定义一个函数,也可以像对象一样拥有属性和方法</p> <pre>interface Lib { (): void version: string doSomething(): void } let lib: Lib = (() =&gt; {}) as Lib lib.version = '1.0' lib.doSomething = () =&gt; {} </pre> <p>我们可以创造多个lib实例</p> <pre>function getLib() { let lib: Lib = (() =&gt; {}) as Lib lib.version = '1.0' lib.doSomething = () =&gt; {} return lib } let lib1 = getLib() lib1() lib1.doSomething() let lib2 = getLib() </pre> <div class="alert alert-success" role="alert"><p>来源:<code>https://www.cnblogs.com/xfxing/p/12652266.html</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Tue, 07 Apr 2020 03:54:35 +0000 依然范特西╮ 3553555 at https://www.e-learn.cn 大话接口隐私与安全 https://www.e-learn.cn/topic/3553060 <span>大话接口隐私与安全</span> <span><span lang="" about="/user/231" typeof="schema:Person" property="schema:name" datatype="">安稳与你</span></span> <span>2020-04-07 10:29:37</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <p>作为后端程序猿自己写的<code>接口</code>就像自己的<code>孩子</code>一样,尽然制造出来了,那就要对他以后的人生负责到底;<br /> 随着业务的壮大,需要支撑业务接口也越来越多,使用的用户量变大,虎视眈眈的黑客们视机而动,总是在业务中寻找着可以窃取他人利益的入口,所以我们应该多考虑安全性问题,防范于未然。</p> <p><img alt="安全" class="b-lazy" data-src="https://static.oschina.net/uploads/img/201611/16090816_wLqm.jpg" data-original="https://static.oschina.net/uploads/img/201611/16090816_wLqm.jpg" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /></p> <span id="OSC_h2_1"></span> <h2>场景</h2> <p>服务端程序猿根据需求开发出业务相关的接口,用来满足需求中用户和服务器交互的功能,提供给前端或者客户端(PC端软件,APP端应用)使用, 大部分程序猿在开发接口的时候就仅仅去考虑如何实现业务上的逻辑功能,而往往很少会去考虑接口的安全性问题, 一般服务端提供的接口都是http/https协议的,通过Fiddler,Wireshark,Charles等抓包工具,可以抓取到请求,然后进行分析,模拟请求,进行并发请求,或者修改信息的攻击。</p> <span id="OSC_h2_2"></span> <h2>例子:</h2> <span id="OSC_h3_3"></span> <h3>问题1. 接口暴露用户隐私信息就相当于在光天化日下裸奔,被看光了</h3> <blockquote> <p>描述:程序猿在做业务接口的时候往往没有保护用户隐私的意识,把用户的隐私信息暴露在外面,一旦被人利用起来会给用户带来麻烦,同时被发现会降低平台的信任度;</p> </blockquote> <span id="OSC_h4_4"></span> <h4>防:</h4> <ol><li>用户隐私数据加密,加*号,如用户的相关数据的JSON中有用户手机号,用户邮箱,支付账号,邮寄地址等隐私数据;</li> <li>用户请求接口时需要对其隐私参数加密:如用户登陆请求登陆接口,需要将用户密码进行可逆加密,以免接口被恶意代理捕捉请求后获取明文密码;</li> <li>分享出去的地址中不要用明文的用户ID,或者用户登录的token</li> </ol><span id="OSC_h3_5"></span> <h3>问题2. 接口暴露敏感信息,就像把钥匙插在钥匙口没拔掉一样,只要你会开门就能进去</h3> <blockquote> <p>用户参与活动的数据JSON集合中不要有活动相关业务逻辑的决定性的数据,如:竞拍出价活动,出价唯一最低者拿奖品,结果获取出价的接口暴露了所有出价的价格统计结果。</p> </blockquote> <span id="OSC_h4_6"></span> <h4>防:</h4> <ol><li>数据中需要将敏感字段,或者对业务有着决定性作用的字段中的部分字符串加*;</li> </ol><span id="OSC_h3_7"></span> <h3>问题3.数据被人顺手带走(主业务接口相关JSON数据 如:首页商品列表数据)</h3> <blockquote> <p>描述:接口中的JSON数据会被其他人拿去做自己的相关的功能;这样就造成了服务器的额外支出</p> </blockquote> <span id="OSC_h4_8"></span> <h4>防:</h4> <ol><li>IP请求量限制,时间范围内请求量限制,等各种限制IP请求的规则, <br /> 如:统计记录(可以记录到mongdb中),定时监控记录发现请求量大于限制的数量就进行IP封杀;</li> <li>请求头的校验,如:User-Agent 校验请求头是不是APP客服端发起,Referer 是不是有来源,来源域名是不是自己的域名地址等(这种方式只能是多一个门槛);</li> </ol><span id="OSC_h3_9"></span> <h3>问题4.移花接木,恶意修改请求信息(修改参数,COOKIE,请求头信息)</h3> <blockquote> <p>描述:通过修改请求中的参数来发起的请求,如:登陆接口修改用户名和用户密码,进行密码库碰撞等。</p> </blockquote> <blockquote> <p>温馨提示:<br /> 修改请求参数可能会导致很多安全性问题,如:SQL注入,XSS 跨站脚本攻击等,传送门我的【<a href="http://blog.thankbabe.com/2016/04/03/Safe/" target="_blank" rel="nofollow">大话程序猿眼里的WEB安全</a>】有相关的介绍和解决方案 <br /> 以下方案都针对客户端,如PC软件和APP,WEB端JS去做加密的话不是很推荐,JS代码是暴露出来的,所以如果用JS做加密一定要混淆JS代码</p> </blockquote> <span id="OSC_h4_10"></span> <h4>防:</h4> <ol><li> <p>增加一个签名参数,将参数名进行逻辑的排序组合拼接+秘钥MD5,然后服务端接受到请求的时候也用同样的逻辑得到签名与签名参数进行对比是否相同,这样可以使参数无法被修改,修改了就提示非法请求。 如: 接口http://www.test.com/go/?actid=1&amp;userid=123 我们可以加一个sign参数= MD5(actid=1&amp;userid=123&amp;【secret】)【secret】=秘钥,自己定义。 服务端用一样的逻辑得到密文和sign签名进行对比是否一样,不一样就提示非法请求。</p> </li> <li>整个参数内容进行可逆的加密</li> <li>限制参数范围,如:支持分页接口,很多人会为了方便使用,加了参数就是pagesize(一页的数据量),当没有去限制页码最大值得时候,如果表数据量很大,然后攻击者修改pagesize参数为N万,然后数据库就奔溃了,相关业务就挂了。</li> </ol><span id="OSC_h3_11"></span> <h3>问题5.影分身术,模拟请求,发起并发请求</h3> <blockquote> <p>描述:通过抓包工具抓到请求后模拟请求,如:模拟每日签到请求,或者直接发起每日签到的并发请求。 <br /> 温馨提示:当请求并发后如何保证数据的完整性,一致性问题,这也是平时开发很需要注意的问题,传送门我的【<a href="http://blog.thankbabe.com/2016/04/01/high-concurrency/" target="_blank" rel="nofollow">大话程序员眼里的高并发</a>】有相关的介绍和解决方案。</p> </blockquote> <span id="OSC_h4_12"></span> <h4>防:</h4> <ol><li>模拟并发请求,IP限制同上问题2的解决方案。</li> <li>请求信息带上时间(可逆加密的时间),服务端获取时间,超过限定时间的返回请求超时(目的使抓取到的请求不是一直有效的)。</li> <li>用户token,等标识用户重要的信息数据,保存COOKIE需要设置过期时间,或者加密的明文里要有创建的时间,服务端做对应的时间失效的限制,这样即使COOKIE被别人盗取,模拟请求也会随着时间而失效;</li> </ol><span id="OSC_h2_13"></span> <h2>总结</h2> <p>我们需要提高自己的安全意识,防范于未然,要多站在攻击者的角度来看自己的接口;(让自己有一种被害妄想症的感觉,你就离精神病近了一步,&lt;( ̄︶ ̄)↗ ) 不要做开发需求的机器人,我们是有思想有创造力的开发者;</p> <span id="OSC_h4_14"></span> <h4>附加个人开发流程</h4> <blockquote> <p>在评审需求的时候要把业务逻辑问题提出来,并给予解决方案的选择; <br /> 确定需求后将整个业务逻辑的梳理清楚,复杂的可以画出流程图; <br /> 根据需求设计实现方案,需要考虑性能问题[数据库压力,服务器压力],安全问题,用文档的形式记录下自己的设计方案。(可以深入到代码层面如何去实现); <br /> 列出需求中功能点,评估出自己的时间,得到总工时; <br /> 开始开发,开干;</p> </blockquote> <div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/1411814/blog/788502</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/yonghujiekou" hreflang="zh-hans">用户接口</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> <div class="field--item"><a href="/tag/chengxuyuan-0" hreflang="zh-hans">程序猿</a></div> </div> </div> Tue, 07 Apr 2020 02:29:37 +0000 安稳与你 3553060 at https://www.e-learn.cn 让SpringMVC支持可版本管理的Restful接口 https://www.e-learn.cn/topic/3551952 <span>让SpringMVC支持可版本管理的Restful接口</span> <span><span lang="" about="/user/161" typeof="schema:Person" property="schema:name" datatype="">隐身守侯</span></span> <span>2020-04-07 06:19:35</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <span id="OSC_h1_1"></span> <h1>需求</h1> <p>移动互联网时代的到来,软件开发的模式也在变化。记得以前做B/S的后台开发,基本上没有Http接口一说,全部是通过渲染模板技术(jsp,freemark)把最终html展示给最终用户。现在完全变了,基于后台接口提供方,我们从来不是针对只是浏览器展示的后台输出,而是各种终端,比如android,ios。所以设计接口的时候一定要小心,一旦放出去的接口可能就永远都难以变动(除非你强制客户端用户升级)。我们知道,<a href="http://en.wikipedia.org/wiki/Representational_state_transfer" target="_blank" rel="nofollow">Restful API</a>已经成为接口设计的一个业务准则。如果你还不是很清楚什么是Restful,推荐你看一下这篇文章: <a href="http://www.ruanyifeng.com/blog/2014/05/restful_api.html" target="_blank" rel="nofollow">RESTful API 设计指南</a>。其实,我们就是设计一套基于http协议的业务接口,但是随着时间变迁,业务的变化,或者我们协议本身的优化,都有可能要改变之前存在的接口。这时候给所有接口进行版本管理就显得很重要了,比如某个添加用户的接口,由于业务发展很大,接口的字段属性变化很大,只能重新定义一个新的接口,由 /v1/user/add 变成了 /v2/user/add,这样我们就要维护两套接口的逻辑,映射到代码里,就是要维护两个不同的业务方法。所以这篇文章主要讲的是基于SpringMVC开发的应用,怎么通过扩展开发来方便我们在代码层级管理各不同的版本接口。</p> <span id="OSC_h1_2"></span> <h1>SpringMVC原理概述</h1> <p>SpringMVC核心思想就是通过一个servlet(DispatchServlet)把请求转发到各个执行方法上(Controller的method),截张官方的图如下:</p> <p></p><p></p><img class="b-lazy" data-src="https://www.eimg.top/images/2020/04/07/edaa5458715160f127b60e8ac50ef79e.jpg" data-original="https://www.eimg.top/images/2020/04/07/edaa5458715160f127b60e8ac50ef79e.jpg" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /><p></p> <p> 就是把某个形式的URL(当然,url不是唯一的决定条件,还有比如请求方法,get还是post,请求头中的信息)映射到某个类的具体方法上,这个核心的组件在SpringMVC中叫做: HandlerMapping。我们一般在spring的config文件中做如下配置时会自动初始化加载一个HanlderMapping的实现类:RequestMappingHandlerMapping:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> </td> <td> <p><code>&lt;mvc:annotation-driven/&gt;</code></p> </td> </tr></tbody></table><p>至于这个一行的配置干了什么,可以从org.springframework.web.servlet.config.MvcNamespaceHandler这个类开始看进去。我们现在来定义一个Controller,如下:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> </td> <td> <p><code><a href="http://my.oschina.net/u/1774615" class="referer" target="_blank" rel="nofollow">@Controller</a></code></p> <p><code>public</code> <code>class</code> <code>HelloController {</code></p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"hello/"</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha1.........."</code><code>);</code></p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p>这样我们通过 /hello/ 就可以调用了。现在假如我们针对这个接口的业务出现了很大的变化(涉及到字段,报文的改变,和之前的不能兼容),但是老的接口又不能废弃,因为你不能保证放出去的接口没有人调用。所以我们只能把代码改成如下支持多个版本接口:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p> <p>16</p> <p>17</p> <p>18</p> </td> <td> <p><code><a href="http://my.oschina.net/u/1774615" class="referer" target="_blank" rel="nofollow">@Controller</a></code></p> <p><code>public</code> <code>class</code> <code>HelloController {</code></p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"v1/hello/"</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello1(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha1.........."</code><code>);</code></p> <p><code>        </code> </p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>    </code> </p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"v2/hello/"</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello2(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha2........."</code><code>);</code></p> <p><code>        </code> </p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p>现在我们就可以通过 /v1/hello, /v2/hello 来分别访问v1和v2两个版本对应的接口了。这看起来好像可以解决问题,因为我们每次某个接口有变动,只要新写一个对应该版本的方法就可以了。但是相应的问题也就来了:</p> <ul><li>我们一般发布出去的接口,都是以http://api.custom.com/v1,http://api.custom.com/v2发布出去的,从v1到v2,往往我们只会变动其中一小部分接口,但是客户端必需统一版本号调用 。 </li> <li>不能智能向上兼容接口。如果现在我们某个接口最高版本是v2,如 /v2/hello, 现在通过 /v3/hello 要能够自动适配到 /v2/hello上。</li> </ul><p>所以我们通过Spring强大的扩展机制增加几个扩展类来完成这个工作。先看下SringMVC中HandlerMapping加载初始化和动态根据url到handler的流程:</p> <p></p><p></p><img class="b-lazy" data-src="https://www.eimg.top/images/2020/04/07/3cac28c62e4d65f7bd5e0b4792998bdf.jpg" data-original="https://www.eimg.top/images/2020/04/07/3cac28c62e4d65f7bd5e0b4792998bdf.jpg" src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" /><p></p> <p> 可以看到,HandlerMapping就是通过继承InitializingBean接口在完成实例后,扫描所有的Controller和标识RequestMapping的方法,缓存这个映射对应关系。然后在应用运行的时候,根据请求的request来找到相应的handler来处理这个请求。所以,我们添加扩展类:</p> <ul><li>ApiVersion</li> <li>ApiVesrsionCondition</li> <li>CustomRequestMappingHandlerMapping</li> <li>WebConfig</li> </ul><p>现分别来看下这个类,首先看下ApiVersion这个注解:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> </td> <td> <p><code>@Target</code><code>({ElementType.METHOD, ElementType.TYPE})</code></p> <p><code>@Retention</code><code>(RetentionPolicy.RUNTIME)</code></p> <p><code>@Documented</code></p> <p><code>@Mapping</code></p> <p><code>public</code> <code>@interface</code> <code>ApiVersion {</code></p> <p><code>    </code><code>/**</code></p> <p><code>     </code><code>* 版本号</code></p> <p><code>     </code><code>* @return</code></p> <p><code>     </code><code>*/</code></p> <p><code>    </code><code>int</code> <code>value();</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p>这个注解用来标识某个类或者方法要处理的对应版本号,使用如下:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p> <p>16</p> <p>17</p> <p>18</p> <p>19</p> <p>20</p> <p>21</p> <p>22</p> <p>23</p> <p>24</p> <p>25</p> <p>26</p> <p>27</p> <p>28</p> <p>29</p> <p>30</p> <p>31</p> </td> <td> <p><code>@Controller</code></p> <p><code>@RequestMapping</code><code>(</code><code>"/{version}/"</code><code>)</code></p> <p><code>public</code> <code>class</code> <code>HelloController {</code></p> <p> </p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"hello/"</code><code>)</code></p> <p><code>    </code><code>@ApiVersion</code><code>(</code><code>1</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha1.........."</code><code>);</code></p> <p><code>        </code> </p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>    </code> </p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"hello/"</code><code>)</code></p> <p><code>    </code><code>@ApiVersion</code><code>(</code><code>2</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello2(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha2........."</code><code>);</code></p> <p><code>        </code> </p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>    </code> </p> <p><code>    </code><code>@RequestMapping</code><code>(</code><code>"hello/"</code><code>)</code></p> <p><code>    </code><code>@ApiVersion</code><code>(</code><code>5</code><code>)</code></p> <p><code>    </code><code>@ResponseBody</code></p> <p><code>    </code><code>public</code> <code>String hello5(HttpServletRequest request){</code></p> <p><code>        </code><code>System.out.println(</code><code>"haha5........."</code><code>);</code></p> <p><code>        </code> </p> <p><code>        </code><code>return</code> <code>"hello"</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p>现在我们就可以通过 /v1/hello/, /v2/hello/, /v5/hello来分别调用版本1,2,5的管理。当然我们也要解决刚才说的两点问题,如果用户通过 /v4/hello/来访问接口,则要自动适配到 /v2/hello/,因为 v2是比v4低的版本中最新的版本。</p> <p>再来看下 ApiVersionCondition 这个类。这个类就是我们自定义一个条件筛选器,让SpringMVC在原有逻辑的基本上添加一个版本号匹配的规则:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p> <p>16</p> <p>17</p> <p>18</p> <p>19</p> <p>20</p> <p>21</p> <p>22</p> <p>23</p> <p>24</p> <p>25</p> <p>26</p> <p>27</p> <p>28</p> <p>29</p> <p>30</p> <p>31</p> <p>32</p> <p>33</p> <p>34</p> <p>35</p> <p>36</p> </td> <td> <p><code>public</code> <code>class</code> <code>ApiVesrsionCondition </code><code>implements</code> <code>RequestCondition&lt;ApiVesrsionCondition&gt; {</code></p> <p> </p> <p><code>    </code><code>// 路径中版本的前缀, 这里用 /v[1-9]/的形式</code></p> <p><code>    </code><code>private</code> <code>final</code> <code>static</code> <code>Pattern VERSION_PREFIX_PATTERN = Pattern.compile(</code><code>"v(\\d+)/"</code><code>);</code></p> <p><code>    </code> </p> <p><code>    </code><code>private</code> <code>int</code> <code>apiVersion;</code></p> <p><code>    </code> </p> <p><code>    </code><code>public</code> <code>ApiVesrsionCondition(</code><code>int</code> <code>apiVersion){</code></p> <p><code>        </code><code>this</code><code>.apiVersion = apiVersion;</code></p> <p><code>    </code><code>}</code></p> <p><code>    </code> </p> <p><code>    </code><code>public</code> <code>ApiVesrsionCondition combine(ApiVesrsionCondition other) {</code></p> <p><code>        </code><code>// 采用最后定义优先原则,则方法上的定义覆盖类上面的定义</code></p> <p><code>        </code><code>return</code> <code>new</code> <code>ApiVesrsionCondition(other.getApiVersion());</code></p> <p><code>    </code><code>}</code></p> <p> </p> <p><code>    </code><code>public</code> <code>ApiVesrsionCondition getMatchingCondition(HttpServletRequest request) {</code></p> <p><code>        </code><code>Matcher m = VERSION_PREFIX_PATTERN.matcher(request.getPathInfo());</code></p> <p><code>        </code><code>if</code><code>(m.find()){</code></p> <p><code>            </code><code>Integer version = Integer.valueOf(m.group(</code><code>1</code><code>));</code></p> <p><code>            </code><code>if</code><code>(version &gt;= </code><code>this</code><code>.apiVersion) </code><code>// 如果请求的版本号大于配置版本号, 则满足</code></p> <p><code>                </code><code>return</code> <code>this</code><code>;</code></p> <p><code>        </code><code>}</code></p> <p><code>        </code><code>return</code> <code>null</code><code>;</code></p> <p><code>    </code><code>}</code></p> <p> </p> <p><code>    </code><code>public</code> <code>int</code> <code>compareTo(ApiVesrsionCondition other, HttpServletRequest request) {</code></p> <p><code>        </code><code>// 优先匹配最新的版本号</code></p> <p><code>        </code><code>return</code> <code>other.getApiVersion() - </code><code>this</code><code>.apiVersion;</code></p> <p><code>    </code><code>}</code></p> <p> </p> <p><code>    </code><code>public</code> <code>int</code> <code>getApiVersion() {</code></p> <p><code>        </code><code>return</code> <code>apiVersion;</code></p> <p><code>    </code><code>}</code></p> <p> </p> <p><code>}</code></p> </td> </tr></tbody></table><p>要把这个筛选规则生效的话,要扩展原胡的HandlerMapping,把这个规则设置进去生效,看下CustomRequestMappingHandlerMapping的代码:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> <p>12</p> <p>13</p> <p>14</p> <p>15</p> <p>16</p> <p>17</p> <p>18</p> </td> <td> <p><code>public</code> <code>class</code> <code>CustomRequestMappingHandlerMapping </code><code>extends</code> <code>RequestMappingHandlerMapping {</code></p> <p> </p> <p><code>    </code><code>@Override</code></p> <p><code>    </code><code>protected</code> <code>RequestCondition&lt;ApiVesrsionCondition&gt; getCustomTypeCondition(Class&lt;?&gt; handlerType) {</code></p> <p><code>        </code><code>ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType, ApiVersion.</code><code>class</code><code>);</code></p> <p><code>        </code><code>return</code> <code>createCondition(apiVersion);</code></p> <p><code>    </code><code>}</code></p> <p> </p> <p><code>    </code><code>@Override</code></p> <p><code>    </code><code>protected</code> <code>RequestCondition&lt;ApiVesrsionCondition&gt; getCustomMethodCondition(Method method) {</code></p> <p><code>        </code><code>ApiVersion apiVersion = AnnotationUtils.findAnnotation(method, ApiVersion.</code><code>class</code><code>);</code></p> <p><code>        </code><code>return</code> <code>createCondition(apiVersion);</code></p> <p><code>    </code><code>}</code></p> <p><code>    </code> </p> <p><code>    </code><code>private</code> <code>RequestCondition&lt;ApiVesrsionCondition&gt; createCondition(ApiVersion apiVersion) {</code></p> <p><code>        </code><code>return</code> <code>apiVersion == </code><code>null</code> <code>? </code><code>null</code> <code>: </code><code>new</code> <code>ApiVesrsionCondition(apiVersion.value());</code></p> <p><code>    </code><code>}</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p> </p> <p> 最后,得让SpringMVC加载我们定义的CustomRequestMappingHandlerMapping以覆盖原先的RequestMappingHandlerMapping, 所以要去掉前面说的&lt;mvc:annotation-driven/&gt;这个配置,我们通过JavaConfig的方式注入:</p> <table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td> <p>1</p> <p>2</p> <p>3</p> <p>4</p> <p>5</p> <p>6</p> <p>7</p> <p>8</p> <p>9</p> <p>10</p> <p>11</p> <p>12</p> </td> <td> <p><code>@Configuration</code></p> <p><code>public</code> <code>class</code> <code>WebConfig </code><code>extends</code> <code>WebMvcConfigurationSupport{</code></p> <p> </p> <p><code>    </code><code>@Override</code></p> <p><code>    </code><code>@Bean</code></p> <p><code>    </code><code>public</code> <code>RequestMappingHandlerMapping requestMappingHandlerMapping() {</code></p> <p><code>        </code><code>RequestMappingHandlerMapping handlerMapping = </code><code>new</code> <code>CustomRequestMappingHandlerMapping();</code></p> <p><code>        </code><code>handlerMapping.setOrder(</code><code>0</code><code>);</code></p> <p><code>        </code><code>handlerMapping.setInterceptors(getInterceptors());</code></p> <p><code>        </code><code>return</code> <code>handlerMapping;</code></p> <p><code>    </code><code>}</code></p> <p><code>}</code></p> </td> </tr></tbody></table><p>Over!</p> <p>详细代码: <a href="https://github.com/hongfuli/study_notes/tree/master/spring/samples" rel="nofollow">https://github.com/hongfuli/study_notes/tree/master/spring/samples</a></p> <p> </p> <p>参考:</p> <p><a href="http://stackoverflow.com/questions/10312177/how-to-implement-requestmapping-custom-properties/10336769#10336769" rel="nofollow">http://stackoverflow.com/questions/10312177/how-to-implement-requestmapping-custom-properties/10336769#10336769</a></p> <p><a href="https://jira.spring.io/browse/SPR-9344" rel="nofollow">https://jira.spring.io/browse/SPR-9344</a></p> <div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/2876959/blog/736063</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/banbenguanli" hreflang="zh-hans">版本管理</a></div> <div class="field--item"><a href="/tag/springmvczhujie" hreflang="zh-hans">springmvc注解</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Mon, 06 Apr 2020 22:19:35 +0000 隐身守侯 3551952 at https://www.e-learn.cn es6 Iterator接口和for-of https://www.e-learn.cn/topic/3551912 <span>es6 Iterator接口和for-of</span> <span><span lang="" about="/user/169" typeof="schema:Person" property="schema:name" datatype="">亡梦爱人</span></span> <span>2020-04-07 06:05:47</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"> <h1>iterator接口</h1> <ul><li>简介: <ul><li>Iterator 接口的目的,就是为所有数据结构,提供了一种统一的访问机制,即for...of循环(详见下文)。当使用for...of循环遍历某种数据结构时,该循环会自动去寻找 Iterator 接口。</li> </ul></li> <li>iterator接口遍历过程 <ol><li>创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。</li> <li>第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。</li> <li>第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。</li> <li>不断调用指针对象的next方法,直到它指向数据结构的结束位置。</li> </ol></li> <li>凡是具有Symbol.iterator属性的数据就具备for-of遍历的功能 <ul><li>Symbol.iterator本身是一个函数,该函数返回一个具有next方法的对象(简称遍历对象),next方法则是返回一个获取下一个成员的信息</li> <li>遍历对象除了有next方法,还可以部署return和throw方法 <ul><li>return方法的使用场合是,如果for...of循环提前退出(通常是因为出错,或者有break语句),就会调用return方法。如果一个对象在完成遍历前,需要清理或释放资源,就可以部署return方法。</li> <li>throw方法主要是配合 Generator 函数使用,一般的遍历器对象用不到这个方法</li> <li><strong>下面见例子</strong> <ul><li>例子一:</li> </ul><pre><code>next:()=&gt;({ value:value,//返回下一个成员的值 done:false // 判断是否遍历到结尾了 }) </code></pre> <ul><li>例子二:</li> </ul><pre><code>var it = makeIterator(['a', 'b']); it.next() // { value: "a", done: false } it.next() // { value: "b", done: false } it.next() // { value: undefined, done: true } function makeIterator(array) { var nextIndex = 0; return { next: function() { return nextIndex &lt; array.length ? {value: array[nextIndex++], done: false} : {value: undefined, done: true}; } }; } </code></pre> <ul><li>例子三:</li> </ul><pre><code> let arr = ['a', 'b', 'c']; let iter = arr[Symbol.iterator](); iter.next() // { value: 'a', done: false } iter.next() // { value: 'b', done: false } iter.next() // { value: 'c', done: false } iter.next() // { value: undefined, done: true } </code></pre> </li> </ul></li> </ul></li> <li>原生具备Iterator接口的数据类型有: <ul><li>Array</li> <li>Map</li> <li>Set</li> <li>String</li> <li>TypedArray</li> <li>函数的 arguments 对象</li> <li>NodeList 对象</li> </ul></li> </ul><hr /><h1>for-of</h1> <ul><li>一个数据结构只要部署了Symbol.iterator属性,就被视为具有 iterator 接口,就可以用for...of循环遍历它的成员。 也就是说,for...of循环内部调用的是数据结构的Symbol.iterator方法。</li> <li>forEach遍历无法通过break命令或return命令跳出循环,除非抛出错误</li> <li>for-of可以和break、continue和return配合使用,且简洁</li> </ul><div class="alert alert-success" role="alert"><p>来源:<code>oschina</code></p><p>链接:<code>https://my.oschina.net/u/3407699/blog/2222975</code></p></div></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/iterator" hreflang="zh-hans">iterator</a></div> <div class="field--item"><a href="/tag/shujujiegou" hreflang="zh-hans">数据结构</a></div> <div class="field--item"><a href="/tag/bianli" hreflang="zh-hans">遍历</a></div> <div class="field--item"><a href="/tag/jiekou" hreflang="zh-hans">接口</a></div> </div> </div> Mon, 06 Apr 2020 22:05:47 +0000 亡梦爱人 3551912 at https://www.e-learn.cn