小米彈出式相機專利曝光,採反射鏡機構解決前後鏡頭拍攝需求_包裝設計

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

近年許多手機品牌都為了讓手機擁有更大的螢幕占比,無論是早期的瀏海螢幕、水滴螢幕,到後來彈出升降式前鏡頭、翻轉鏡頭或挖孔螢幕,甚至是今年有望正式量產的螢幕下前鏡頭,不過上述做法都是解決螢幕體驗和前鏡頭的自拍需求。日前,小米也向美國專利商標局和世界智慧財產權組織申請了一項相機專利,藉由彈出式機構搭配反射透鏡,讓它同時能解決以往對於前後的鏡頭的拍攝需求。

▲圖片來源:LetsGoDigital

小米彈出式相機專利曝光,採反射鏡機構解決前後鏡頭拍攝需求

去年至今年目前這段期間,在螢幕挖孔的設計已經能說是目前中階、旗艦手機的趨勢。近日外媒 LetsGoDital 曝光了小米向美國專利商標局和世界智慧財產權組織申請最新的相機專利,則帶來不同以往的相機結構。這項新專利利用相似於彈出式相機的設計,但在升降出來的並非相機模組,而是一組帶有反射鏡的機構。
它將相機鏡頭本體隱藏於手機內部朝上,並透過彈出的反射鏡機構將外界光線反射至相機鏡頭進行拍攝。同時,小米也針對這項設計設計旋轉機構,可將反射鏡旋轉 180° ,完成正反面的影像拍攝需求。

▲圖片來源:LetsGoDigital

倘若這項專利正式量產至手機上,未來在機身正反面將不再有可見的相機鏡頭,機身背面設計也將更為簡化、甚至不排除能有更多空間配備像是小米 MIX 那般全環繞螢幕手機。目前還未確定小米這項專利將在何時才有機會實現並量產,不過傳聞在今年下半年將有多款採用螢幕下前鏡頭的手機會在市場推出。

消息來源:LetsGoDigital

延伸閱讀:
小米 Redmi 系列首款支援雙 5G 的 Redmi Note 9T 5G 以及 6000mAh 大電量 Redmi 9T 在台推出

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

POCO M3 開箱、評測|6000mAh 大電量超乎想像,極致性價比王者重返台灣市場

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

Web 三維組態的仿真運用案例:民航飛機的數據監控_網頁設計公司

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

前言 在飛機航行的過程中,客艙里座位上方的熒屏上,除了播放電視劇和廣告之外,還會時不時的切換到一個飛機航行的監控系統。這個監控系統的主要目的是,讓乘客可以了解到飛機在航行過程中的整體狀況、距離目的地的航線進程以及一些有可能出現的突發事件。飛機航行的監控系統在一定程度上,可以使乘客在旅途過程中得到準確的信息源,最重要的是可以使乘客在旅途中得到安心。在保障乘客獲取到實際信息源的同時,飛機航行的監控系統也能將採集到的數據及時的反饋給航務人員,而且將數據記錄保存下來,在飛機過站或航后供航務和機務人員使用和監測維護。介於 2D 組態和 3D 組態上,
Hightopo(以下簡稱 HT )的 
HT for Web 產品上的有着豐富的組態化可供選擇,本文將介紹如何運用 HT 豐富的 
2/3D 組態搭建出一個飛機航行的監控系統的解決方案。 預覽地址: flight-monitor  
系統分析 飛機航行監控是一種測量、跟蹤飛機性能變化趨勢的簡單而實用方法。在日常航班飛行中,用機載儀錶記錄飛機巡航時的有關參數,並將其與原有性能進行比較。監控的主要參數有:飛行單位時間消耗的燃油量、飛機的巡航飛行速度和消耗單位燃油量飛機飛過的水平距離。它們分別表示發動機、飛機及飛機發動機的綜合性能。它們分別表示發動機、飛機及飛機發動機的綜合性能。性能監控的結果,既可為飛機維修提供可能的故障信息,又為制定飛行計劃提供可靠的性能依據。 目前,先進的噴氣運輸機都已安裝飛行狀態監控系統,它記錄下有關參數值,並存儲在數據管理裝置中,這些數據可以發送到或在飛機着陸後送到地面站,用專用計算機程序進行計算和修正,使性能監控數據採集、發送、計箅分析工作自動化,節省了人力,提高了精確度。 1、
飛行數據記錄器:自從飛行數據記錄器 FDR(Flight Data Recorder)“俗稱黑匣子”誕生以來,其提供的詳實準確的飛行數據為事故調查、機務維護保障、安全運營監控提供了重要依據,成為航空安全運營的重要管理手段。 2、
ACMS(Aireraft Condition Monitoring System)的系統概述:ACMS 系統是飛機上安裝的先進機載數據採集和處理系統,它能以實時方式收集數據,對發動機狀態和飛行性能進行監控以及進行特殊的工程調查。由飛機通信尋址與報告系統(ACARS)通過地空數據鏈發送到地面接收站,最後傳送到航空公司的終端,也可通過快速存取記錄器(QAR)將數據記錄保存下來,在飛機過站或航后供航務和機務人員使用。 而 HT 實現的業務功能可以通過ACMS 系統採集到的數據,對接到显示終端去展示,通過實時監測的數據準確地显示出來,起到對飛機狀態的監控功能並即時反饋信息數據的變化。  
實現過程
雲中穿行效果 為了達到飛機雲中穿行的效果,最開始我遇到的問題是飛機飛行的層次感,也就通常所說的透視效果,這裏我採用的是雲通道和雲背景以不同的速度流動,製造一種飛行的透視效果。   雲我採用的是貼圖的方式呈現的,但是僅僅是貼圖會遮擋天空和飛機,非常影響飛機飛行的觀感,所以我開啟了相應圖元的 
transparent 和 
opacity,雲背景和雲通道設置不同的透明度,不僅增加了層次感,還會讓人產生雲朵從眼前飄過的錯覺。   雲通道採用的是 
ht.Polyline 類型,通道縮放拉大了 Y 軸的比例,使雲通道有更大的縱向空間,設置 
reverse.flip 背拷貝使雲通道內部也显示出貼圖,彷彿讓飛機置身於雲海中穿梭;雲背景採用 
ht.Node 類型,只設置一個面显示充當雲背景。   整體的雲流動效果採用 
offset 偏移實現,改變相應圖元或相應圖元面的貼圖偏移量來達到飛機雲中穿行的效果, 代碼如下:

var i = 1, p = 0; setInterval(() => { i -= 0.1; p += 0.005; clouds.s('shape3d.uv.offset', [i, 0]); cloudBackground.s('all.uv.offset', [p, 0]); }, 100);

 

升降顛簸效果 雖然達到了飛機雲中穿行的效果,但是如果飛機只是直直的飛行,那也會降低飛行的實感,相信坐過飛機的朋友肯定都遇到過因氣流產生的顛簸,也經常感受到飛機飛行途中的爬升和下降,這其實是因為飛機的航線並不是一直固定在一個高度上,有時會爬升有時會下降,所以我就用 
ht-animation.js HT 動畫擴展插件去實現飛機顛簸效果,代碼如下:

dm.enableAnimation(20);
plane.setAnimation({
    back1: {
        from: 0, to: 160, easing: 'Cubic.easeInOut', duration: 8000, next: "up1", onUpdate: function (value) { value = parseInt(value); var p3 = this.p3(); this.p3(value, p3[1], p3[2]); } }, //...省略相似 start: ["back1"] });

 

球扇形視角限制 飛行效果完善之後,這時我就遇到了一個比較棘手的問題,因為實際上雖然看着飛機是在雲海中穿梭,但是僅僅是在通道中飛行,背景其實也只是平面貼圖,所以當視角到達某種程度的時候就會有強烈的違和感和不真實感,就需要一個視角限制,使視角的調整剛剛好在一個範圍內。   視角限制的話一般是限制 g3d 的 
eye 和 
center,不太了解的朋友可以去看 hightopo 官網中的 3d 手冊,裏面有詳細的說明,這裏我就不再贅述了;因為視角範圍的關係,所以我決定固定 
center 的位置,代碼如下:

g3d.addPropertyChangeListener(e => {
    // 固定中心點 if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = center[2]; } }

然後再把 eye 限制在某一個範圍內就大功告成了,然而這裏卻並不是那麼簡單,最開始我把 eye 限制在一個立方體的空間內,但交互效果很不理想,考慮到 g3d 默認交互中,鼠標拖拽平移視角變換時,實際上 eye 是在一個以 center 為球心的球面上運動的,所以我決定從這個球中挖出來一塊作為 eye 的限制空間,也就是球扇形,不太理解的朋友可以參考這個圖:

 

球扇形視角限制,一共需要三個參數,分別是中心參考軸、中心軸和外邊所成角度、所在球限制半徑,其中中心參考軸可根據初始 eye 和 center 的連接延長線確定,所在球限制半徑又分最大限制和最小限制,代碼如下:

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

function limitEye(g3d, eye, center, options) { var limitMaxL = options.limitMaxL, limitMinL = options.limitMinL, limitA = options.limitA; g3d.addPropertyChangeListener(e => { // 固定中心點 if (e.property === 'center') { e.newValue[0] = center[0]; e.newValue[1] = center[1]; e.newValue[2] = center[2]; } // 限制視角 if (e.property === 'eye') { var newEyeV = new ht.Math.Vector3(e.newValue), centerV = new ht.Math.Vector3(center), refEyeV = new ht.Math.Vector3(eye), refVector = refEyeV.clone().sub(centerV), newVector = newEyeV.clone().sub(centerV); if (centerV.distanceTo(newEyeV) > limitMaxL) { newVector.setLength(limitMaxL); e.newValue[0] = newVector.x; e.newValue[1] = newVector.y; e.newValue[2] = newVector.z; } if (centerV.distanceTo(newEyeV) < limitMinL) { newVector.setLength(limitMinL); e.newValue[0] = newVector.x; e.newValue[1] = newVector.y; e.newValue[2] = newVector.z; } if (newVector.angleTo(refVector) > limitA) { var oldLength = newVector.length(), oldAngle = newVector.angleTo(refVector), refLength = oldLength * Math.cos(oldAngle), vertVector, realVector, realEye; refVector.setLength(refLength); newEyeV = newVector.clone().add(centerV); refEyeV = refVector.clone().add(centerV); vertVector = newEyeV.clone().sub(refEyeV); vertLength = refLength * Math.tan(limitA); vertVector.setLength(vertLength); realVector = vertVector.clone().add(refEyeV).sub(centerV); realVector.setLength(oldLength); realEye = realVector.clone().add(centerV); // 防止移動角度大於 180 度,視角反轉 if (oldAngle > Math.PI / 2) { realEye.negate(); } e.newValue[0] = realEye.x; e.newValue[1] = realEye.y; e.newValue[2] = realEye.z; } } }) }

 

飛機監控系統 當然作為監控系統,自然要有監控了,增加右下角的小地圖,並提供三種模式,分別是聚焦飛機,聚焦飛行軌跡和聚焦地圖,並根據飛機的飛行方向控制飛行軌跡的流動效果,其中聚焦飛機會跟隨飛機移動進行 
fitData,使飛機一直處於小地圖的中心,代碼如下:

var fitFlowP = function (e) { if (e.property === 'position' && e.data === plane) { mapGV.fitData(plane, false); } }; buttonP.s({ 'interactive': true, 'onClick': function (event, data, view, point, width, height) { map.a('fitDataTag', 'plane2D'); mapGV.fitData(plane, false); mapDM.md(fitFlowP); } }); buttonL.s({ 'interactive': true, 'onClick': function (event, data, view, point, width, height) { mapDM.umd(fitFlowP); map.a('fitDataTag', 'flyLine'); mapGV.fitData(flyLine, false); } }); // ...省略

增加鼠標移到飛機相應位置進行名稱的提示、雙擊后显示飛機相應位置的信息面板並將視角聚焦到面板上、點擊飛機任意地方切換回飛機飛行模式等效果。 左側增加監控面板替代上面提到的雙擊相應位置這步操作直接聚焦到相應位置的信息面板上,這裏按鈕開啟了交互並添加了相應的交互邏輯,代碼如下:

button_JC.s({
    'interactive': true, 'onClick': function (event, data, view, point, width, height) { event.preventDefault(); let g3d = G.g3d, g3dDM = G.g3d.dm(); g3d.fireInteractorEvent({ kind: 'doubleClickData', data: g3dDM.getDataByTag(data.getTag()) }) } }); //...省略

 

天空渲染效果 既然是監控系統肯定是 24 小時無差別的監控,這就涉及到一個問題,我總不可能半夜的時候飛機也從瓦藍瓦藍的天空上飛過,這就很欠缺真實性了,所以要有一個天空從亮到暗再從暗到亮的過程,這個過程我暫定到 06:00-06:30 和19:00-19:30 這兩個時間段。   天空採用的是 
shape3d : ‘sphere’ 球形,包裹整個場景,然後使用 
reverse.flip 背拷貝 和 
blend 染色,之後天空就可以渲染成我想要的顏色,如果按照時間改變天空明暗只要改變染色值就可以了。   但是由於白天和晚上光照情況的不同,雲反射光的強度也不同,就導致了白天和晚上雲的差異,所以也要調整雲道和雲背景的貼圖的 
opacity 透明度,晚間更為透明度,代碼如下:

if ((hour > 6 && hour < 19) || (hour == 6 && minutes >= 30)) { timePane && timePane.a({ 'morning.visible': false, 'day.visible': true, 'dusk.visible': false, 'night.visible': false, 'day.opacity': 1 }) skyBox.s({ "shape3d.blend": 'rgb(127, 200, 240)', }) cloudBackground.s({ "back.opacity": 0.7, }) clouds.s({ "shape3d.opacity": 0.7, }) } else if ((hour < 6 || hour > 19) || (hour == 19 && minutes >= 30)) { //...省略 } else if (hour == 6 && minutes < 15 ) { //...省略 } else if (hour == 6 && minutes >= 15 && minutes < 30) { //...省略 } else if (hour == 19 && minutes < 15) { //...省略 } else if (hour == 19 && minutes >= 15 && minutes < 30) { //...省略 }

 

這裏我還增加了對右上角時間面板時間狀態圖標的支持,並增加了圖標切換時的漸隱漸顯效果,同時給時間面板狀態圖標位置增加了點擊切換到下一時間狀態的功能。   為了演示效果我增加了時間倍速按鈕,下圖是 500 倍時間流速下的變化情況:  
總結 身處大數據時代的我們,在網絡科技發展越來越快的環境下,迎來了 5G 的新征程和工業4.0的新變革,在信息數據採集傳輸和數據可視化系統的融合下,可以發掘出許多行業管控可視化系統的解決方案。而 HT 長久以來一直致力於多樣化行業系統可視化的搭建,涉獵的技術行業所累積的經驗,通過自主創新研發的技術產品,已經打造出許多行業上具有代表性意義的可視化管控系統,例如同樣有關於飛機的監控可視化系統: 無人機 3D 可視化系統 2019 我們也更新了數百個工業互聯網 2D/3D 可視化案例集,在這裏你能發現許多新奇的實例,也能發掘出不一樣的工業互聯網: https://mp.weixin.qq.com/s/ZbhB6LO2kBRPrRIfHlKGQA 同時,你也可以查看更多案例及效果: https://www.hightopo.com/demos/index.html 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

容器技術之Dockerfile(二)_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

  前文我們聊到了什麼是dockerfile,它的主要作用以及dockerfile的一些基本指令的使用方法,回顧請參考https://www.cnblogs.com/qiuhom-1874/p/13019411.html;今天我們在來聊一聊dockerfile餘下指令的用法和作用;

  1、RUN:該指令用於docker build 過程中運行的程序,可以是任何命令;語法格式RUN <command> 或RUN [“<executable>”, “<param1>”, “<param2>”];第一種格式中,<command>通常是一個shell命令,且以“/bin/sh -c”來運行它,這意味着此進程在容器中的PID不為1,不能接收Unix信號,因此,當使用docker stop <container>命令停止容器時,此進程接收不到SIGTERM信號; 第二種語法格式中的參數是一個JSON格式的數組,其中<executable>為要運行的命令,後面的<paramN>為傳遞給命令的選項或參數;然而,此種格式指定的命令不會以“/bin/sh -c”來發起,因此常見的shell操作如變量替換以及通配符(?,*等)替換將不會進行;不過,如果要運行的命令依賴於此shell特性的話,可以將其替換為 RUN [“/bin/sh”, “-c”, “<executable>”, “<param1>”]這樣的格式;注意:json數組中,要使用雙引號;

  示例:

[root@node1 test]# cat Dockerfile 
FROM centos:7 

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

RUN mkdir -p /aaa/bbb/t{1..4}



[root@node1 test]# 

  提示:以上Dockerfile中,用RUN指令運行了mkdir命令,這種運行命令的方式在就可以利用shell的特性,如上大括號展開功能;

  驗證:build 該dockerfile后,運行該鏡像為容器,看看容器內部是否創建了/aaa/bbb/t1 t2 t3 t4?

[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
busybox             latest              1c35c4412082        16 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker build . -t myimg:v1
Sending build context to Docker daemon   1.05MB
Step 1/9 : FROM centos:7
 ---> b5b4d78bc90c
Step 2/9 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Running in 64c792ce6750
Removing intermediate container 64c792ce6750
 ---> 604899ef29f9
Step 3/9 : LABEL version="1.0"
 ---> Running in 6a3f9b4a9058
Removing intermediate container 6a3f9b4a9058
 ---> d9edea71fa22
Step 4/9 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Running in b191ab5e19f9
Removing intermediate container b191ab5e19f9
 ---> ee027bbdc04b
Step 5/9 : ARG web_home
 ---> Running in a4c86febf616
Removing intermediate container a4c86febf616
 ---> 5b25bb7421dd
Step 6/9 : COPY html ${web_home:-"/data/htdoc/"}
 ---> 7c7a667149fa
Step 7/9 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Running in f9ec02d8f736
Removing intermediate container f9ec02d8f736
 ---> 86c7226f6b21
Step 8/9 : EXPOSE 80/tcp 443/tcp
 ---> Running in ad82d389ac25
Removing intermediate container ad82d389ac25
 ---> 28dadea40aff
Step 9/9 : RUN mkdir -p /aaa/bbb/t{1..4}
 ---> Running in 1013a212d3f2
Removing intermediate container 1013a212d3f2
 ---> 7f109a34a4a5
Successfully built 7f109a34a4a5
Successfully tagged myimg:v1
[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1                  7f109a34a4a5        4 seconds ago       203MB
busybox             latest              1c35c4412082        16 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker run --name test --rm -it myimg:v1 /bin/bash
[root@fc89ca934ed5 /]# ls /
aaa                bin   dev  home  lib64  mnt  proc  run   srv  tmp  var
anaconda-post.log  data  etc  lib   media  opt  root  sbin  sys  usr
[root@fc89ca934ed5 /]# ls /aaa/
bbb
[root@fc89ca934ed5 /]# ls /aaa/bbb/
t1  t2  t3  t4
[root@fc89ca934ed5 /]# exit
exit
[root@node1 test]# 

  提示:底層基礎鏡像的shell如果不支持大括號展開,那麼我們基於這種鏡像做出來的鏡像運行以上命令也就不支持shell的大括號展開功能;

  示例:

[root@node1 test]# cat Dockerfile
FROM centos:7

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

RUN mkdir -p /aaa/bbb/t{1..4}

RUN ["mkdir","-p","/ccc/ddd/f{1..4}"]

[root@node1 test]# 

  提示:以json數組格式的方式去運行命令,它默認是不支持shell的任何特性,這意味着運行該命令時,不是基於shell子進程的方式在執行命令,通常是內核直接執行了;所以上面的命令它會把大括號處理成字符,而不會展開;

  驗證:build成鏡像運行成容器,看看是否把大括號處理成字符了?

[root@node1 test]# docker build . -t myimg:v1.1
Sending build context to Docker daemon   1.05MB
Step 1/10 : FROM centos:7
 ---> b5b4d78bc90c
Step 2/10 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> 604899ef29f9
Step 3/10 : LABEL version="1.0"
 ---> Using cache
 ---> d9edea71fa22
Step 4/10 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> ee027bbdc04b
Step 5/10 : ARG web_home
 ---> Using cache
 ---> 5b25bb7421dd
Step 6/10 : COPY html ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 7c7a667149fa
Step 7/10 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 86c7226f6b21
Step 8/10 : EXPOSE 80/tcp 443/tcp
 ---> Using cache
 ---> 28dadea40aff
Step 9/10 : RUN mkdir -p /aaa/bbb/t{1..4}
 ---> Using cache
 ---> 7f109a34a4a5
Step 10/10 : RUN ["mkdir","-p","/ccc/ddd/f{1..4}"]
 ---> Running in 9da1e6bab59f
Removing intermediate container 9da1e6bab59f
 ---> ae463ec8cbd9
Successfully built ae463ec8cbd9
Successfully tagged myimg:v1.1
[root@node1 test]# docker run --name test --rm -it myimg:v1.1 /bin/bash
[root@02ec6e404100 /]# ls /
aaa                bin  data  etc   lib    media  opt   root  sbin  sys  usr
anaconda-post.log  ccc  dev   home  lib64  mnt    proc  run   srv   tmp  var
[root@02ec6e404100 /]# ls /ccc/ddd/
f{1..4}
[root@02ec6e404100 /]# 

  提示:可以看到在/ccc/ddd/目錄下並沒有把大括號展開,而是直接把它當成了字符處理了;如果我們想要用json數組這種方式運行命令,又想讓使用shell特性,我們可以使用”/bin/sh -c”來明確聲明後面的命令用shell子進程的方式運行;如下所示

[root@node1 test]# cat Dockerfile
FROM centos:7

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

RUN mkdir -p /aaa/bbb/t{1..4}

RUN ["/bin/bash","-c","mkdir -p /ccc/ddd/f{1..4}"]

[root@node1 test]# 

  提示:以上運行命令的方式就明確聲明使用shell子進程的方式運行命令;這裏需要注意一點的是,如果使用json數組的方式運行命令,後面真正執行的命令要一個整體當作參數傳給”/bin/bash”

  驗證:看看是否會把大括號展開?

[root@node1 test]# docker build . -t myimg:v1.2
Sending build context to Docker daemon   1.05MB
Step 1/10 : FROM centos:7
 ---> b5b4d78bc90c
Step 2/10 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> 604899ef29f9
Step 3/10 : LABEL version="1.0"
 ---> Using cache
 ---> d9edea71fa22
Step 4/10 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> ee027bbdc04b
Step 5/10 : ARG web_home
 ---> Using cache
 ---> 5b25bb7421dd
Step 6/10 : COPY html ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 7c7a667149fa
Step 7/10 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 86c7226f6b21
Step 8/10 : EXPOSE 80/tcp 443/tcp
 ---> Using cache
 ---> 28dadea40aff
Step 9/10 : RUN mkdir -p /aaa/bbb/t{1..4}
 ---> Using cache
 ---> 7f109a34a4a5
Step 10/10 : RUN ["/bin/bash","-c","mkdir -p /ccc/ddd/f{1..4}"]
 ---> Running in a5785a139e1f
Removing intermediate container a5785a139e1f
 ---> 30a5f5594104
Successfully built 30a5f5594104
Successfully tagged myimg:v1.2
[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.2                30a5f5594104        5 seconds ago       203MB
myimg               v1.1                ae463ec8cbd9        9 minutes ago       203MB
myimg               v1                  7f109a34a4a5        21 minutes ago      203MB
busybox             latest              1c35c4412082        16 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker run --name test --rm -it myimg:v1.2 /bin/bash
[root@549f875aa4de /]# ls /
aaa                bin  data  etc   lib    media  opt   root  sbin  sys  usr
anaconda-post.log  ccc  dev   home  lib64  mnt    proc  run   srv   tmp  var
[root@549f875aa4de /]# ls /ccc/ddd/
f1  f2  f3  f4
[root@549f875aa4de /]# 

  提示:可以看到用”/bin/bash -c” 是可以明確聲明後面的命令用shell子進程的方式運行,這樣一來就可以在後面的命令使用shell特性的語法;

  2、CMD:該指令類似於RUN指令,CMD指令也可用於運行任何命令或應用程序,不過,二者的運行時間點不同; RUN指令運行於映像文件構建過程中,而CMD指令運行於基於Dockerfile構建出的新映像文件啟動一個容器時; CMD指令的首要目的在於為啟動的容器指定默認要運行的程序,且其運行結束后,容器也將終止;不過,CMD指定的命令其可以被docker run的命令行選項所覆蓋;在Dockerfile中可以存在多個CMD指令,但僅最後一個會生效;語法格式 CMD <command> 或 CMD [“<executable>”, “<param1>”, “<param2>”] 或 CMD [“<param1>”,”<param2>”];前兩種語法格式的意義同RUN,第三種則用於為ENTRYPOINT指令提供默認參數;

  示例:

[root@node1 test]# cat Dockerfile
FROM busybox:latest

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

CMD httpd -f -h /data/htdoc/
[root@node1 test]# 

  提示:docker容器內部運行的程序必須運行為前台;CMD是指定容器運行時要運行的命令;通常該命令或程序是以前台方式運行;如果不是前台運行,我們的容器就會存在一啟動就退出的情況;以上命令就表示前台運行httpd程序 並指定httpd 的工作目錄為${web_home}變量所指定的目錄;

  驗證:build后看看啟動為容器是否提供80訪問服務?

[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.2                30a5f5594104        23 minutes ago      203MB
myimg               v1.1                ae463ec8cbd9        32 minutes ago      203MB
myimg               v1                  7f109a34a4a5        44 minutes ago      203MB
busybox             latest              1c35c4412082        16 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker build . -t myimg:v1.3
Sending build context to Docker daemon   1.05MB
Step 1/9 : FROM busybox:latest
 ---> 1c35c4412082
Step 2/9 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Running in deb5e54eef87
Removing intermediate container deb5e54eef87
 ---> baf170e0c586
Step 3/9 : LABEL version="1.0"
 ---> Running in 433669185e0d
Removing intermediate container 433669185e0d
 ---> d96fb4ae3d58
Step 4/9 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Running in b5da74e27c69
Removing intermediate container b5da74e27c69
 ---> 62372d19daf3
Step 5/9 : ARG web_home
 ---> Running in 3f65a67bb15a
Removing intermediate container 3f65a67bb15a
 ---> 1ce797c7cde0
Step 6/9 : COPY html ${web_home:-"/data/htdoc/"}
 ---> 15848dea21b9
Step 7/9 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Running in 868f4c10e00f
Removing intermediate container 868f4c10e00f
 ---> f3ec40d1cb5e
Step 8/9 : EXPOSE 80/tcp 443/tcp
 ---> Running in 7f72c2612e92
Removing intermediate container 7f72c2612e92
 ---> 5ccfc6d604cc
Step 9/9 : CMD httpd -f -h /data/htdoc/
 ---> Running in 95a4fd578821
Removing intermediate container 95a4fd578821
 ---> 2e296b4f4500
Successfully built 2e296b4f4500
Successfully tagged myimg:v1.3
[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.3                2e296b4f4500        3 seconds ago       1.22MB
myimg               v1.2                30a5f5594104        23 minutes ago      203MB
myimg               v1.1                ae463ec8cbd9        33 minutes ago      203MB
myimg               v1                  7f109a34a4a5        44 minutes ago      203MB
busybox             latest              1c35c4412082        16 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker run --name b1 -d myimg:v1.3
c3514f782cffd8140aa7c612293029f4d0302e8d697887dfc2696eea44a31700
[root@node1 test]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
c3514f782cff        myimg:v1.3          "/bin/sh -c 'httpd -…"   4 seconds ago       Up 3 seconds        80/tcp, 443/tcp     b1
[root@node1 test]# curl http://172.17.0.2/test1.html
this is test1 html
[root@node1 test]# 

  提示:可以看到httpd是可以正常提供服務的;從上面的信息我們也可以了解到運行容器后,它默認是把我們寫的命令當作shell子命令的方式在運行;

  示例:以json數組方式運行命令

[root@node1 test]# cat Dockerfile 
FROM busybox:latest

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

CMD ["httpd","-f","-h","/data/htdoc/"]

[root@node1 test]# 

  提示:用json數組格式運行命令,需要把後面的每個選項當作參數傳給httpd;

  驗證:運行容器看看容器是否退出,是否能夠正常提供httpd服務?

[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.3                2e296b4f4500        24 minutes ago      1.22MB
myimg               v1.2                30a5f5594104        47 minutes ago      203MB
myimg               v1.1                ae463ec8cbd9        57 minutes ago      203MB
myimg               v1                  7f109a34a4a5        About an hour ago   203MB
busybox             latest              1c35c4412082        17 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker build . -t myimg:v1.4
Sending build context to Docker daemon   1.05MB
Step 1/9 : FROM busybox:latest
 ---> 1c35c4412082
Step 2/9 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> baf170e0c586
Step 3/9 : LABEL version="1.0"
 ---> Using cache
 ---> d96fb4ae3d58
Step 4/9 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> 62372d19daf3
Step 5/9 : ARG web_home
 ---> Using cache
 ---> 1ce797c7cde0
Step 6/9 : COPY html ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 15848dea21b9
Step 7/9 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> f3ec40d1cb5e
Step 8/9 : EXPOSE 80/tcp 443/tcp
 ---> Using cache
 ---> 5ccfc6d604cc
Step 9/9 : CMD ["httpd","-f","-h","/data/htdoc/"]
 ---> Running in 5bebdabfe2b7
Removing intermediate container 5bebdabfe2b7
 ---> 58e3b4c40ae7
Successfully built 58e3b4c40ae7
Successfully tagged myimg:v1.4
[root@node1 test]# docker run --name b1 -d myimg:v1.4
a32a05033a6dcb735363906bfcd2b84cfb290ca1b60c17d3ac2f81cdeceee705
[root@node1 test]# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
a32a05033a6d        myimg:v1.4          "httpd -f -h /data/h…"   6 seconds ago       Up 5 seconds        80/tcp, 443/tcp     b1
[root@node1 test]# curl http://172.17.0.2/test1.html
this is test1 html
[root@node1 test]# 

  提示:可以看到httpd服務可以正常提供訪問,說明我們用json數組方式運行命令是正確的;總結一點,用CMD或RUN指令運行命令時,如果直接在CMD或RUN指令後面接命令,這種方式通常會被解釋為啟動一個shell子進程運行命令,RUN指令表現形式就是後面的命令可以使用shell特性的語法格式的命令,比如大括號展開等等;而CMD指令表現形式就是啟動為容器后,它默認會把我們指定運行的命令當作參數傳給“/bin/sh”來運行;CMD或RUN指令加中括號的形式就表示使用json數組格式方式運行命令;這種方式運行命令在CMD中表現形式是我們運行的命令的選項都要當作參數傳給該命令;RUN指令表現形式是不能使用shell特性的命令;如果非要使用shell特性的命令格式,我們需要把我們的命令當作參數傳給“/bin/sh”,當然前提是我們的基礎鏡像shell支持shell特性的語法;

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

  3、ENTRYPOINT:該指令類似CMD指令的功能,用於為容器指定默認運行程序,從而使得容器像是一個單獨的可執行程序;與CMD不同的是,由ENTRYPOINT啟動的程序不會被docker run命令行指定的參數所覆蓋,而且,這些命令行參數會被當作參數傳遞給ENTRYPOINT指定的程序(不過,docker run命令的–entrypoint選項的參數可覆蓋ENTRYPOINT指令指定的程序);語法格式 ENTRYPOINT <command>或 ENTRYPOINT [“<executable>”, “<param1>”, “<param2>”];docker run命令傳入的命令參數會覆蓋CMD指令的內容並且附加到ENTRYPOINT命令最後做為其參數使用;Dockerfile文件中也可以存在多個ENTRYPOINT指令,但僅有最後一個會生效;

  示例:

[root@node1 test]# cat Dockerfile
FROM busybox:latest

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

ENTRYPOINT httpd -f -h /data/htdoc/
[root@node1 test]# 

  提示:以上dockerfile中用ENTRYPOINT 來指定容器默認運行程序,它和CMD不同的是,CMD指定運行的命令,我們可以使用docker run 命令加要運行的的命令替代容器里默認運行的命令,而ENTRYPOINT指定的命令我們是不可隨便替換的,如果要替換必須要使用–entrypoint選項來指定;

  驗證:build成鏡像,我們啟動為容器直接運行/bin/sh 看看是否可行?

[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.4                58e3b4c40ae7        23 minutes ago      1.22MB
myimg               v1.3                2e296b4f4500        47 minutes ago      1.22MB
myimg               v1.2                30a5f5594104        About an hour ago   203MB
myimg               v1.1                ae463ec8cbd9        About an hour ago   203MB
myimg               v1                  7f109a34a4a5        2 hours ago         203MB
busybox             latest              1c35c4412082        17 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker build . -t myimg:v1.5
Sending build context to Docker daemon   1.05MB
Step 1/9 : FROM busybox:latest
 ---> 1c35c4412082
Step 2/9 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> baf170e0c586
Step 3/9 : LABEL version="1.0"
 ---> Using cache
 ---> d96fb4ae3d58
Step 4/9 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> 62372d19daf3
Step 5/9 : ARG web_home
 ---> Using cache
 ---> 1ce797c7cde0
Step 6/9 : COPY html ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> 15848dea21b9
Step 7/9 : VOLUME ${web_home:-"/data/htdoc/"}
 ---> Using cache
 ---> f3ec40d1cb5e
Step 8/9 : EXPOSE 80/tcp 443/tcp
 ---> Using cache
 ---> 5ccfc6d604cc
Step 9/9 : ENTRYPOINT httpd -f -h /data/htdoc/
 ---> Running in de274d68686c
Removing intermediate container de274d68686c
 ---> 5825c2ec655f
Successfully built 5825c2ec655f
Successfully tagged myimg:v1.5
[root@node1 test]# docker run --name b1 --rm -it myimg:v1.5 /bin/sh

  提示:運行以上命令后,不會給我們一個shell終端,也不報錯;但是我們直接訪問httpd服務是可以正常訪問的;這意味我們用docker run 命令是不能替換我們用entrypoint指定指定的命令的;

  測試:用–entrypoint 選項來看看是否能夠覆蓋ENTRYPOINT指定所指定的命令程序?

[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
myimg               v1.5                5825c2ec655f        12 minutes ago      1.22MB
myimg               v1.4                58e3b4c40ae7        35 minutes ago      1.22MB
myimg               v1.3                2e296b4f4500        About an hour ago   1.22MB
myimg               v1.2                30a5f5594104        About an hour ago   203MB
myimg               v1.1                ae463ec8cbd9        2 hours ago         203MB
myimg               v1                  7f109a34a4a5        2 hours ago         203MB
busybox             latest              1c35c4412082        17 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker run --name b1 --rm -it --entrypoint "/bin/sh" myimg:v1.5
/ # ls
bin   data  dev   etc   home  proc  root  sys   tmp   usr   var
/ # ps
PID   USER     TIME  COMMAND
    1 root      0:00 /bin/sh
    7 root      0:00 ps
/ # 

  提示:可以看到使用docker run 必須要加–entrypoint 選項才可以覆蓋ENTRYPOINT指令指定的命令;

  示例:使用json數組格式來指定命令

[root@node1 test]# cat Dockerfile 
FROM busybox:latest

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

ARG web_home

COPY html ${web_home:-"/data/htdoc/"}

VOLUME ${web_home:-"/data/htdoc/"}

EXPOSE 80/tcp 443/tcp

ENTRYPOINT ["httpd","-f","-h","/data/htdoc/"]

[root@node1 test]# 

  提示:使用json數組格式來指定命令時,都需要將後面的選項和參數當作該命令的參數傳進去;

  測試:使用docker run 直接加命令 看看是否能夠覆蓋ENTRYPOINT指令指定的命令?

  提示:可以看到我們直接使用命令是無法覆蓋ENTRYPOINT指令說指定的命令;

  示例:

[root@node1 test]# cat Dockerfile 
FROM centos:7

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

RUN yum install -y httpd

EXPOSE 80/tcp 

ENTRYPOINT ["/usr/sbin/httpd","-DFOREGROUND"]

[root@node1 test]# 

  測試:用docker run 命令覆蓋ENTRYPOINT指定的默認命令,看看是否可行?

[root@node1 test]# docker build . -t myimg:v1.7
Sending build context to Docker daemon  1.051MB
Step 1/7 : FROM centos:7
 ---> b5b4d78bc90c
Step 2/7 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> 604899ef29f9
Step 3/7 : LABEL version="1.0"
 ---> Using cache
 ---> d9edea71fa22
Step 4/7 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> ee027bbdc04b
Step 5/7 : RUN yum install -y httpd
 ---> Running in 164240645e39
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
 * base: mirrors.aliyun.com
 * extras: mirrors.aliyun.com
 * updates: mirrors.aliyun.com
Resolving Dependencies
--> Running transaction check
---> Package httpd.x86_64 0:2.4.6-93.el7.centos will be installed
--> Processing Dependency: httpd-tools = 2.4.6-93.el7.centos for package: httpd-2.4.6-93.el7.centos.x86_64
--> Processing Dependency: system-logos >= 7.92.1-1 for package: httpd-2.4.6-93.el7.centos.x86_64
--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-93.el7.centos.x86_64
--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-93.el7.centos.x86_64
--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-93.el7.centos.x86_64
--> Running transaction check
---> Package apr.x86_64 0:1.4.8-5.el7 will be installed
---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed
---> Package centos-logos.noarch 0:70.0.6-3.el7.centos will be installed
---> Package httpd-tools.x86_64 0:2.4.6-93.el7.centos will be installed
---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

================================================================================
 Package             Arch          Version                    Repository   Size
================================================================================
Installing:
 httpd               x86_64        2.4.6-93.el7.centos        base        2.7 M
Installing for dependencies:
 apr                 x86_64        1.4.8-5.el7                base        103 k
 apr-util            x86_64        1.5.2-6.el7                base         92 k
 centos-logos        noarch        70.0.6-3.el7.centos        base         21 M
 httpd-tools         x86_64        2.4.6-93.el7.centos        base         92 k
 mailcap             noarch        2.1.41-2.el7               base         31 k

Transaction Summary
================================================================================
Install  1 Package (+5 Dependent packages)

Total download size: 24 M
Installed size: 32 M
Downloading packages:
warning: /var/cache/yum/x86_64/7/base/packages/apr-util-1.5.2-6.el7.x86_64.rpm: Header V3 RSA/SHA256 Signature, key ID f4a80eb5: NOKEY
Public key for apr-util-1.5.2-6.el7.x86_64.rpm is not installed
--------------------------------------------------------------------------------
Total                                              7.8 MB/s |  24 MB  00:03     
Retrieving key from file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Importing GPG key 0xF4A80EB5:
 Userid     : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
 Fingerprint: 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
 Package    : centos-release-7-8.2003.0.el7.centos.x86_64 (@CentOS)
 From       : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : apr-1.4.8-5.el7.x86_64                                       1/6 
  Installing : apr-util-1.5.2-6.el7.x86_64                                  2/6 
  Installing : httpd-tools-2.4.6-93.el7.centos.x86_64                       3/6 
  Installing : centos-logos-70.0.6-3.el7.centos.noarch                      4/6 
  Installing : mailcap-2.1.41-2.el7.noarch                                  5/6 
  Installing : httpd-2.4.6-93.el7.centos.x86_64                             6/6 
  Verifying  : mailcap-2.1.41-2.el7.noarch                                  1/6 
  Verifying  : apr-util-1.5.2-6.el7.x86_64                                  2/6 
  Verifying  : httpd-2.4.6-93.el7.centos.x86_64                             3/6 
  Verifying  : apr-1.4.8-5.el7.x86_64                                       4/6 
  Verifying  : httpd-tools-2.4.6-93.el7.centos.x86_64                       5/6 
  Verifying  : centos-logos-70.0.6-3.el7.centos.noarch                      6/6 

Installed:
  httpd.x86_64 0:2.4.6-93.el7.centos                                            

Dependency Installed:
  apr.x86_64 0:1.4.8-5.el7                                                      
  apr-util.x86_64 0:1.5.2-6.el7                                                 
  centos-logos.noarch 0:70.0.6-3.el7.centos                                     
  httpd-tools.x86_64 0:2.4.6-93.el7.centos                                      
  mailcap.noarch 0:2.1.41-2.el7                                                 

Complete!
Removing intermediate container 164240645e39
 ---> 63db91f4fe6a
Step 6/7 : EXPOSE 80/tcp
 ---> Running in 6585da71fc3b
Removing intermediate container 6585da71fc3b
 ---> eb671cf67f52
Step 7/7 : ENTRYPOINT ["/usr/sbin/httpd","-DFOREGROUND"]
 ---> Running in f6e7297025af
Removing intermediate container f6e7297025af
 ---> bac03b20761a
Successfully built bac03b20761a
Successfully tagged myimg:v1.7
[root@node1 test]# docker run --name m1 --rm -it myimg:v1.7 /bin/sh
Usage: /usr/sbin/httpd [-D name] [-d directory] [-f file]
                       [-C "directive"] [-c "directive"]
                       [-k start|restart|graceful|graceful-stop|stop]
                       [-v] [-V] [-h] [-l] [-L] [-t] [-T] [-S] [-X]
Options:
  -D name            : define a name for use in <IfDefine name> directives
  -d directory       : specify an alternate initial ServerRoot
  -f file            : specify an alternate ServerConfigFile
  -C "directive"     : process directive before reading config files
  -c "directive"     : process directive after reading config files
  -e level           : show startup errors of level (see LogLevel)
  -E file            : log startup errors to file
  -v                 : show version number
  -V                 : show compile settings
  -h                 : list available command line options (this page)
  -l                 : list compiled in modules
  -L                 : list available configuration directives
  -t -D DUMP_VHOSTS  : show parsed vhost settings
  -t -D DUMP_RUN_CFG : show parsed run settings
  -S                 : a synonym for -t -D DUMP_VHOSTS -D DUMP_RUN_CFG
  -t -D DUMP_MODULES : show all loaded modules 
  -M                 : a synonym for -t -D DUMP_MODULES
  -t                 : run syntax check for config files
  -T                 : start without DocumentRoot(s) check
  -X                 : debug mode (only one worker, do not detach)
[root@node1 test]# 

  提示:可以看到我們用docker run指定命令去覆蓋ENTRYPOINT指令指定的命令,它給我們打印了httpd命令的用法,這說明我們後面傳遞的/bin/sh 當作參數傳遞給ENTRYPOINT說指定的命令;這裏還需要說一下,上面的示例用docker run 去覆蓋ENTRYPOINT指令指定的命令,沒有報錯的原因應該是busybox里的httpd程序支持傳遞/bin/sh當作參數;

  示例:CMD指令同ENTRYPOINT一起使用

[root@node1 test]# cat Dockerfile 
FROM centos:7

MAINTAINER "qiuhom <qiuhom@linux-1874.com>"

LABEL version="1.0"

LABEL description="this is test file \ that label-values can span multiple lines."

RUN yum install -y httpd

ADD entrypoint.sh /bin/

EXPOSE 80/tcp 

CMD ["/usr/sbin/httpd","-DFOREGROUND"]

ENTRYPOINT ["/bin/entrypoint.sh"]

[root@node1 test]# 

  提示:以上dockerfile使用了CMD和ENTRYPOINT指令來指定容器默認運行程序;此時CMD所指定的命令默認會以參數的形式傳給ENTRYPOINT指令所指定的命令;而上面ENTRYPOINT指定指定的是一個腳本,也就說上面dockerfile最終運行的命令是/bin/entrypoint.sh /usr/sbin/httpd -DFOREGROUND;這裏的腳本就相當於中間層,通過腳本設定一些參數,然後把CMD指定的命令當作參數傳給腳本,最終腳本運行起來;

  entrypoint腳本

[root@node1 test]# ll
total 1032
-rw-r--r-- 1 root root     307 Jun  3 11:28 Dockerfile
-rwxr-xr-x 1 root root     300 Jun  3 11:22 entrypoint.sh
drwxr-xr-x 2 root root      42 May 31 01:51 html
-rw-r--r-- 1 root root 1043748 May 26 11:07 nginx-1.19.0.tar.gz
-rw-r--r-- 1 root root      22 May 31 01:52 test.html
[root@node1 test]# cat entrypoint.sh 
#!/bin/bash

doc_root=${DOC_ROOT:-/var/www/html}
cat > /etc/httpd/conf.d/myweb.conf <<EOF
        <virtualhost *:80>
                servername "localhost"
                documentroot "${doc_root}"
                <directory "${doc_root}">
                        options none
                        allowoverride none
                        require  all granted
                </directory>
        </virtualhost>
EOF

exec "$@"
[root@node1 test]# 

  提示:這個腳本很簡單就是在/etc/httpd/conf.d/生成一個myweb.conf的配置文件,然後最後引用腳本的參數運行;exec “$@” 表示把腳本的所有參數獨立運行成一個守護進程;默認不使用exec就表示以shell子進程的方式運行,exec就表示運行為單獨的守護進程,不再是shell子進程的方式;

  測試:

[root@node1 test]# docker build . -t httpd:v1
Sending build context to Docker daemon  1.051MB
Step 1/9 : FROM centos:7
 ---> b5b4d78bc90c
Step 2/9 : MAINTAINER "qiuhom <qiuhom@linux-1874.com>"
 ---> Using cache
 ---> 604899ef29f9
Step 3/9 : LABEL version="1.0"
 ---> Using cache
 ---> d9edea71fa22
Step 4/9 : LABEL description="this is test file \ that label-values can span multiple lines."
 ---> Using cache
 ---> ee027bbdc04b
Step 5/9 : RUN yum install -y httpd
 ---> Using cache
 ---> 63db91f4fe6a
Step 6/9 : ADD entrypoint.sh /bin/
 ---> 49d1270c3aa3
Step 7/9 : EXPOSE 80/tcp
 ---> Running in 3dacf6acf23b
Removing intermediate container 3dacf6acf23b
 ---> edced77af5b5
Step 8/9 : CMD ["/usr/sbin/httpd","-DFOREGROUND"]
 ---> Running in 23bb32def296
Removing intermediate container 23bb32def296
 ---> 169a5e164ba5
Step 9/9 : ENTRYPOINT ["/bin/entrypoint.sh"]
 ---> Running in f3bf0c267c7b
Removing intermediate container f3bf0c267c7b
 ---> 0801db092665
Successfully built 0801db092665
Successfully tagged httpd:v1
[root@node1 test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               v1                  0801db092665        35 seconds ago      307MB
myimg               v1.7                bac03b20761a        12 minutes ago      307MB
myimg               v1.6                5370df4238eb        2 hours ago         1.22MB
myimg               v1.5                5825c2ec655f        2 hours ago         1.22MB
myimg               v1.4                58e3b4c40ae7        2 hours ago         1.22MB
myimg               v1.3                2e296b4f4500        3 hours ago         1.22MB
myimg               v1.2                30a5f5594104        3 hours ago         203MB
myimg               v1.1                ae463ec8cbd9        3 hours ago         203MB
myimg               v1                  7f109a34a4a5        3 hours ago         203MB
busybox             latest              1c35c4412082        19 hours ago        1.22MB
centos              7                   b5b4d78bc90c        4 weeks ago         203MB
[root@node1 test]# docker run --name h1 -d httpd:v1
cee14b04912822c33e7deeee361e1ce0c20d7daf6c0666bff319bf3f1bc69bdc
[root@node1 test]# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
cee14b049128        httpd:v1            "/bin/entrypoint.sh …"   9 seconds ago       Up 9 seconds        80/tcp              h1
[root@node1 test]# 

  提示:可以看到我們build成鏡像后,直接運行為容器,容器正常;我們進入容器內部看看它到底運行的說明命令

[root@node1 test]# docker exec -it h1 /bin/bash
[root@cee14b049128 /]# ls /etc/httpd/conf.d/myweb.conf 
/etc/httpd/conf.d/myweb.conf
[root@cee14b049128 /]# cat /etc/httpd/conf.d/myweb.conf
        <virtualhost *:80>
                servername "localhost"
                documentroot "/var/www/html"
                <directory "/var/www/html">
                        options none
                        allowoverride none
                        require  all granted
                </directory>
        </virtualhost>
[root@cee14b049128 /]# ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.1 224080  5016 ?        Ss   16:26   0:00 /usr/sbin/httpd -D
apache        7  0.0  0.0 224212  2960 ?        S    16:26   0:00 /usr/sbin/httpd -D
apache        8  0.0  0.0 224212  2960 ?        S    16:26   0:00 /usr/sbin/httpd -D
apache        9  0.0  0.0 224212  2960 ?        S    16:26   0:00 /usr/sbin/httpd -D
apache       10  0.0  0.0 224212  2960 ?        S    16:26   0:00 /usr/sbin/httpd -D
apache       11  0.0  0.0 224212  2960 ?        S    16:26   0:00 /usr/sbin/httpd -D
root         12  0.0  0.0  11828  1932 pts/0    Ss   16:35   0:00 /bin/bash
root         27  0.0  0.0  51756  1720 pts/0    R+   16:36   0:00 ps aux
[root@cee14b049128 /]# httpd -t -D DUMP_VHOSTS
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
VirtualHost configuration:
*:80                   localhost (/etc/httpd/conf.d/myweb.conf:1)
[root@cee14b049128 /]# 

  提示:可以看到容器內部運行的就是/usr/sbin/httpd -DFOREGROUND這個命令;其實這個命令不是CMD直接運行的命令,而是通過腳本獲取參數而來的;我們通過腳本添加的配置文件都在對應的位置,並且也都生效了;總結一點,通常CMD和ENTRYPOINT應用在通過entrypoint腳本做中間層向容器內運行的程序提供配置文件的場景,通常這些應用程序不是雲原生的;

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

系統梳理一下鎖_網頁設計公司

網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

透過選單樣式的調整、圖片的縮放比例、文字的放大及段落的排版對應來給使用者最佳的瀏覽體驗,所以不用擔心有手機版網站兩個後台的問題,而視覺效果也是透過我們前端設計師優秀的空間比例設計,不會因為畫面變大變小而影響到整體視覺的美感。

背景

有人對Java主流鎖做了下面全面的梳理。梳理的確實挺好的。但是我看到這張圖,第一個感覺是:記不住。

  

因為分了太多類,彼此之間沒有什麼聯繫。做PPT可以。如果聊天或者面試,不用紙筆的情況下,就不太好描述了。也不利於對原理和應用的理解。

基於上述的考慮,我就自己系統的梳理一下鎖,希望可以有助於大家理解和記憶,以至於最後在工作中得到很好的應用。

先說線程鎖再說分佈式鎖。

 

線程鎖

概述 

這裏說的線程鎖是Java線程鎖,從原理上各個語言應該都比較相似。有很多維度的劃分方式,我比較建議的是從大面上分為樂觀鎖和悲觀鎖。

樂觀鎖主要是自旋+CAS的方式,比如JUC(java.util.concurrent包)的原子類。 

悲觀鎖主要用synchronized關鍵字的隱式鎖和基於AQS的显示鎖。

上面三段總結如下:

 

悲觀鎖的實現原理

1>synchronized關鍵字

隨着java版本升級,synchronized關鍵字雖然是用C++寫的,但是原理和JCU包的ReentrantLock很相似。synchronized關鍵字有4種鎖狀態:無鎖、偏向鎖、輕量級鎖、重量級鎖。無鎖類似於ReentrantLock的交替執行,沒有併發,就不涉及鎖;偏向鎖類似於ReentrantLock的可重入的概念,使得已經獲取到鎖的線程可以多次獲取鎖;輕量級鎖解決的問題是盡量避免線程切換,使用的方法也和ReentrantLock相似,是自旋+CAS的方式;重量級鎖依賴於管程monitor來實現,和ReentrantLock一樣都涉及用戶態和內核態切換。

根據這個我們再來補充一下Java線程鎖的思維導圖:

南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

搬家費用:依消費者運送距離、搬運樓層、有無電梯、步行距離、特殊地形、超重物品等計價因素後,評估每車次單

 

2>基於基於AQS的显示鎖

基於AQS的显示鎖我之前看過一些源碼。這裏面比較經典的是ReentrantLock。這是可重入鎖,就是同一個線程可以反覆進入加鎖的線程。如果想實現不可重入鎖也很簡單。把可重入鎖對當前線程做特殊處理的部分去掉就好了。

其他JCU下locks包里的鎖比如讀寫鎖就是將鎖細化成了讀鎖和寫鎖。讀鎖是共享鎖的實現,寫鎖是排他鎖的實現。

ReentrantLock可以使用公平鎖和非公平鎖兩種方式,公平鎖和非公平鎖各自繼承了AQS。區別只是非公平鎖在需要加鎖時先直接嘗試是否可以獲取鎖成功,而公平鎖是先看自己是否需要排隊。

下面以ReentrantLock的公平鎖為例來簡單聊一下AQS的源碼。AQS核心是實現了CLH隊列。

AQS有head、tail、持有鎖的線程、狀態4個主要的成員變量。

利用head!=tail就是說AQS是否未被初始化來判斷是否交替執行,交替執行則不用加鎖;如果需要加鎖則判斷是否就是當前擁有鎖的線程,是的話,將進入次數+1;如果不是則判斷是否需要初始化AQS,需要的話先初始化一個dummy header,再將自己加入隊尾,如果是隊列里dummy header的指針指向的節點,則它為先自旋判斷是否可以獲取鎖;如果不是dummy header指針指向的節點,則使用park讓出cpu。當dummy header的指針指向的節點獲取到鎖之後,會將head指向自己,同時將自己這個Node節點的當前線程設置為空,將自己設置為dummy header,同時將原來dummy header的指針都設置為null,使得原dummy header成為一個沒有引用的節點,便於垃圾回收。

根據這個我們再來補充一下Java線程鎖的思維導圖:

 

 

 

 

分佈式鎖

不管是線程鎖還是分佈式鎖,都實現了tryLock、lock、unlock三個方法。

tryLock的語義是非阻塞鎖,嘗試獲取鎖,成功返回true,不成功返回false;主流lock語義是阻塞鎖。實現一般基於tryLock來做自旋,不成功的時候也會有像ReentrantLock一樣的阻塞操作。

常見的分佈式鎖實現以及數據庫鎖的實現詳見之前寫的文章:《MySQL常見6個考題在實際工作中的運用》這裏就不再贅述了。

 

總結

本篇文章在介紹知識點是次要的,主要是展示了總結思考的思路,希望能對讀者朋友們的思考問題方法上有所幫助,僅做參考。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

節能減碳愛地球是景泰電動車的理念,是創立景泰電動車行的初衷,滿意態度更是服務客戶的最高品質,我們的成長來自於你的推薦。

字符串太占內存了,我想了各種奇思淫巧對它進行壓縮_潭子電動車

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

有別於一般網頁架設公司,除了模組化的架站軟體,我們的營業主軸還包含:資料庫程式開發、網站建置、網頁設計、電子商務專案開發、系統整合、APP設計建置、專業網路行銷。

一:背景

1. 講故事

在我們的一個全內存項目中,需要將一家大品牌店鋪小千萬的trade灌入到內存中,大家知道trade中一般會有訂單來源,省市區 ,當把這些字段灌進去后,你會發現他們特別侵蝕內存,因為都是字符串類型,不知道大家對內存侵蝕性是不是很清楚,我就問一個問題。

Question: 一個空字符串佔用多大內存? 你知道嗎?

思考之後,下面我們就一起驗證下,使用windbg去託管堆一查究竟,代碼如下:


        static void Main(string[] args)
        {
            string s = string.Empty;

            Console.ReadLine();
        }

0:000> !clrstack -l
OS Thread Id: 0x308c (0)
        Child SP               IP Call Site
ConsoleApp6.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.cs @ 19]
    LOCALS:
        0x00000087391febd8 = 0x000002605da91420
0:000> !DumpObj /d 000002605da91420
Name:        System.String
String:      
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
00007ff9eb2b85a0  4000281        8         System.Int32  1 instance                0 m_stringLength
00007ff9eb2b6838  4000282        c          System.Char  1 instance                0 m_firstChar
00007ff9eb2b59c0  4000286       d8        System.String  0   shared           static Empty
                                 >> Domain:Value  000002605beb2230:NotInit  <<
0:000> !objsize 000002605da91420
sizeof(000002605da91420) = 32 (0x20) bytes (System.String)

從圖中你可以看到,僅僅一個空字符串就要佔用 32byte,如果500w個空字符串就是: 32byte x 500w = 152M,是不是不算不知道,一算嚇一跳。。。 這還僅僅是一個什麼都沒有的空字符串哦。

2. 回歸到Trade

問題也已經擺出來了,接下來回歸到Trade中,為了方便演示,先模擬以文件的形式從數據庫讀取20w的trade。

    class Program
    {
        static void Main(string[] args)
        {
            var trades = Enumerable.Range(0, 20 * 10000).Select(m => new Trade()
            {
                TradeID = m,
                TradeFrom = File.ReadLines(Environment.CurrentDirectory + "//orderfrom.txt")
                                 .ElementAt(m % 4)
            }).ToList();

            GC.Collect();  //方便測試,把臨時變量清掉
            Console.WriteLine("執行成功");
            Console.ReadLine();
        }
    }

    class Trade
    {
        public int TradeID { get; set; }
        public string TradeFrom { get; set; }
    }

然後用windbg去跑一下託管堆,再量一下trades的大小。


0:000> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
00007ff9eb2b59c0   200200      7010246 System.String

0:000> !objsize 0x000001a5860629a8
sizeof(000001a5860629a8) = 16097216 (0xf59fc0) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

從上面輸出中可以看到託管堆有200200 = 20w(程序分配)+ 200(系統分配)個,然後再看size: 16097216/1024/1024= 15.35M,這就是展示的所有原始情況。

二:壓縮技巧分析

1. 使用字典化處理

其實在託管堆上有20w個字符串,但你仔細觀察一下會發現其實就是4種狀態的重複显示,要麼一淘,要麼淘寶。。。這就給了我優化機會,何不在獲取數據的時候構建好OrderFrom的字典,然後在trade中附增一個TradeFromID記錄字典中的映射值,因為特徵值少,用byte就可以了,有了這個思想,可以把代碼修改如下:

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

日本、大陸,發現這些先進的國家已經早就讓電動車優先上路,而且先進國家空氣品質相當好,電動車節能減碳可以減少空污


    class Program
    {
        public static Dictionary<int, string> orderfromDict = new Dictionary<int, string>();

        static void Main(string[] args)
        {
            var trades = Enumerable.Range(0, 20 * 10000).Select(m =>
            {
                var tradefrom = File.ReadLines(Environment.CurrentDirectory + "//orderfrom.txt")
                                 .ElementAt(m % 4);

                var kv = orderfromDict.FirstOrDefault(k => k.Value == tradefrom);

                if (kv.Key == 0)
                {
                    orderfromDict.Add(orderfromDict.Count + 1, tradefrom);
                }

                var trade = new Trade() { TradeID = m, TradeFromID = (byte)kv.Key };

                return trade;

            }).ToList();

            GC.Collect();  //方便測試,把臨時變量清掉

            Console.WriteLine("執行成功");

            Console.ReadLine();
        }
    }

    class Trade
    {
        public int TradeID { get; set; }

        public byte TradeFromID { get; set; }

        public string TradeFrom
        {
            get
            {
                return Program.orderfromDict[TradeFromID];
            }
        }
    }

代碼還是很簡單的,接下來用windbg看一下空間到底壓縮了多少?

0:000> !dumpheap -stat
Statistics:
              MT    Count    TotalSize Class Name
00007ff9eb2b59c0      204        10386 System.String

0:000> !clrstack -l
OS Thread Id: 0x2ce4 (0)
        Child SP               IP Call Site
ConsoleApp6.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.cs @ 42]
    LOCALS:
        0x0000006f4d9ff078 = 0x0000016fdcf82ab8

0000006f4d9ff288 00007ff9ecd96c93 [GCFrame: 0000006f4d9ff288] 
0:000> !objsize 0x0000016fdcf82ab8
sizeof(0000016fdcf82ab8) = 6897216 (0x693e40) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

從上面的輸出中可以看到,託管堆上string現在是:204 = 4(程序分配) + 200(系統分配)個,這4個就是字典中的4個哦,空間的話:6897216 /1024/1024= 6.57M,對應之前的 15.35M優化了將近60%。

雖然優化了60%,但這種優化是破壞性的優化,需要修改我的Trade結構,同時還要定義個Dictionary,而且還有不小幅度的修改業務邏輯,大家都知道線上的代碼是能不改則不改,不改肯定沒錯,改出問題肯定是你兜着走,是吧,那問題就來了,如何最小化的修改而且還能壓縮空間,有這樣兩全其美的事情嗎???

2. 利用字符串駐留池

貌似一說出來,大家都如夢初醒,駐留池的出現就是為了解決這個問題,CLR會在內部維護了一個我剛才定義的字典機制,重複的字符串就不需要在堆上再次分配,直接存它的引用地址即可,如果你不清楚駐留池,建議看一下我這篇: https://www.cnblogs.com/huangxincheng/p/12799736.html

接下來只需要在tradefrom 字段包一層 string.Intern 即可,改動不要太小,代碼如下:


        static void Main(string[] args)
        {
            var trades = Enumerable.Range(0, 20 * 10000).Select(m => new Trade()
            {
                TradeID = m,
                TradeFrom = string.Intern(File.ReadLines(Environment.CurrentDirectory + "//orderfrom.txt")
                                 .ElementAt(m % 4)),   //包一層 string.Intern
            }).ToList();

            GC.Collect();  //方便測試,把臨時變量清掉
            Console.WriteLine("執行成功");
            Console.ReadLine();
        }

然後用windbg抓一下託管堆。


0:000> !dumpheap -stat 
Statistics:
              MT    Count    TotalSize Class Name
00007ff9eb2b59c0      204        10386 System.String

0:000> !clrstack -l
OS Thread Id: 0x13f0 (0)
        Child SP               IP Call Site

ConsoleApp6.Program.Main(System.String[]) [C:\dream\Csharp\ConsoleApp1\ConsoleApp6\Program.cs @ 27]
    LOCALS:
        0x0000005e4d3ff0a8 = 0x000001f8a15129a8

0000005e4d3ff2b8 00007ff9ecd96c93 [GCFrame: 0000005e4d3ff2b8] 
0:000> !objsize 0x000001f8a15129a8
sizeof(000001f8a15129a8) = 8497368 (0x81a8d8) bytes (System.Collections.Generic.List`1[[ConsoleApp6.Trade, ConsoleApp6]])

觀察后發現,當用了駐留池之後空間為: 8497368 /1024/1024 =8.1M,你可能有疑問,為什麼和字典化相比內存要大24%呢? 仔細觀察你會發現,當用駐留池后,List<Trade> 中的TradeFrom存的是string在堆中的內存地址,在x64機器上要佔用8個字節,而字典化方式內存堆上Trade是不分配TradeFrom,而是用了一個byte來替代,總體來說相當於一個trade省了7byte的空間,然後用windbg看一下。


0:000> !da -length 1 -details 000001f8b16f9b68
Name:        ConsoleApp6.Trade[]
Size:        2097176(0x200018) bytes
Array:       Rank 1, Number of elements 262144, Type CLASS

    Fields:
                      MT    Field   Offset                 Type VT     Attr            Value Name
        00007ff9eb2b85a0  4000001       10             System.Int32      1     instance                    0     <TradeID>k__BackingField
        00007ff9eb2b59c0  4000002        8            System.String      0     instance     000001f8a1516030     <TradeFrom>k__BackingField

0:000> !DumpObj /d 000001f8a1516030
Name:        System.String
String:      WAP

可以看到, 000001f8a1516030 就是 堆上 string=Wap的引用地址,這個地址佔用了8byte空間。

再回頭dump一下使用字典化方式的Trade,可以看到它是沒有 <TradeFrom>k__BackingField 字段的。


0:000> !da -length 1 -details 000001ed52759ac0
Name:        ConsoleApp6.Trade[]
Size:        262168(0x40018) bytes
Array:       Rank 1, Number of elements 32768, Type CLASS
    Fields:
                      MT    Field   Offset                 Type VT     Attr            Value Name
        00007ff9eb2b85a0  4000002        8             System.Int32      1     instance                    0     <TradeID>k__BackingField
        00007ff9eb2b7d20  4000003        c              System.Byte      1     instance                    0     <TradeFromID>k__BackingField


三:總結

大家可以根據自己的情況使用,使用駐留池方式是改變最小的,簡單粗暴,自己構建字典化雖然最省內存,但需要修正業務邏輯,這個風險自擔哦。。。

如您有更多問題與我互動,掃描下方進來吧~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※超省錢租車方案

商務出差、學生出遊、旅遊渡假、臨時用車!GO 神州租賃有限公司!合法經營、合法連鎖、合法租賃小客車!

可以Postman,也可以cURL.進來領略下cURL的獨門絕技_台中搬家公司

※推薦台中搬家公司優質服務,可到府估價

台中搬鋼琴,台中金庫搬運,中部廢棄物處理,南投縣搬家公司,好幫手搬家,西屯區搬家

文章已經收錄在 Github.com/niumoo/JavaNotes ,更有 Java 程序員所需要掌握的核心知識,歡迎Star和指教。
歡迎關注我的公眾號,文章每周更新。

cURL 是一個開源免費項目,主要是命令行工具 cURL 和 libcurl,cURL 可以處理任何網絡傳輸協議,但是不涉及任何具體的數據處理

cURL 支持的通信協議非常豐富,如 DICT,FILE,FTP,FTPS,GOPHER,HTTP,HTTPS,IMAP,IMAPS,LDAP,LDAPS,MQTT,POP3,POP3S,RTMP, RTMPS,RTSP,SCP,SFTP,SMB,SMBS,SMTP,SMTPS,TELNET 以及 TFTP。查看 cURL 源代碼可以訪問官方 Github。

如果安裝 cURL 呢?

ubuntu / Debian.

sudo apt install curl

CentOS / Fedora.

sudo yum install curl

Windows.

如果你已經安裝了 Git,那麼 Git Bash 自帶 cURL . 如果作為開發者你 git 都沒有,那麼只能官方手動下載。

1. 請求源碼

直接 curl 。

$ curl http://wttr.in/

上面請求的示例網址是一個天氣網站,很有意思,會根據你的請求 ip 信息返回你所在位置的天氣情況。

寫這篇文字時我所在的上海正在下雨,窗外飄雨無休無止。

2. 文件下載

使用 -o 保存文件,類似於 wget 命令,比如下載 README 文本保存為 readme.txt 文件。如果你需要自定義文件名,可以使用 -O自定使用 url 中的文件名。

$ curl -o readme.txt https://mirrors.nju.edu.cn/kali/README
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   159  100   159    0     0   1939      0 --:--:-- --:--:-- --:--:--  1939

下載文件會显示下載狀態,如數據量大小、傳輸速度、剩餘時間等。可以使用 -s 參數禁用進度表。

$ curl -o readme.txt https://mirrors.nju.edu.cn/kali/README
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   159  100   159    0     0   1939      0 --:--:-- --:--:-- --:--:--  1939
$ 
$ curl -o readme.txt https://mirrors.nju.edu.cn/kali/README -s

也可以使用 --process-bar 參數讓進度表显示為進度條。

$ curl -o readme.txt https://mirrors.nju.edu.cn/kali/README --progress-bar
########################################################################################## 100.0%

cURL 作為強大的代名詞,斷點續傳自然手到擒來,使用 -C - 參數即可。下面是斷點續傳下載 ubuntu20.04 鏡像的例子。

$ curl -O https://mirrors.nju.edu.cn/ubuntu-releases/20.04/ubuntu-20.04-desktop-amd64.iso --progress-bar
##                                                                                               1.7%
^C
$ curl -C - -O https://mirrors.nju.edu.cn/ubuntu-releases/20.04/ubuntu-20.04-desktop-amd64.iso --progress-bar
###                                                                                              2.4%
^C
$ curl -C - -O https://mirrors.nju.edu.cn/ubuntu-releases/20.04/ubuntu-20.04-desktop-amd64.iso --progress-bar
###                                                                                               2.7%
^C
$ 

什麼?下載時不想佔用太多網速?使用 --limit-rate 限個速吧。

curl -C - -O https://mirrors.nju.edu.cn/ubuntu-releases/20.04/ubuntu-20.04-desktop-amd64.iso --limit-rate 100k

什麼?你又要從 FTP 服務器下載文件了?不慌。

curl -u user:password -O ftp://ftp_server/path/to/file/

3. Response Headers

使用 -i 參數显示 Response Headers 信息。使用 -I 可以只显示 Response Headers 信息。

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

$ curl -I http://wttr.in
HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Sat, 30 May 2020 09:57:03 GMT
Content-Type: text/plain; charset=utf-8
Content-Length: 8678
Connection: keep-alive
Access-Control-Allow-Origin: *

4. 請求方式(GET/POST/…)

使用 -X 輕鬆更改請求方式。

$ curl -X GET http://wttr.in
$ curl -X POST http://wttr.in
$ curl -X PUT http://wttr.in
...

5. 請求參數

以傳入參數 name 值為 未讀代碼 為例。

Get 方式參數直接url拼接參數。

$ curl -X GET http://wttr.in?name=未讀代碼

Post 方式使用 --data 設置參數。

$ curl -X POST --data "name=未讀代碼" http://wttr.in

請求時也可以自定義 header 參數,使用 --harder 添加。

$ curl --header "Content-Type:application/json" http://wttr.in

6. 文件上傳

cURL 的強大遠不止此,表單提交,上傳文件內容也不在話下,只需要使用 -F 或者 -D參數,-F 會自動加上請求頭 Content-Type: multipart/form-data ,而 -D 則是 Content-Type : application/x-www-form-urlencoded.

比如上傳一個 protrait.jpg 圖片。

$ curl -F profile=@portrait.jpg https://example.com/upload

提交一個具有 name 和 age 參數的 form 表單。

curl -F name=Darcy -F age=18 https://example.com/upload

參數對應的內容也可以從文件中讀取。

curl -F "content=<達西的身世.txt" https://example.com/upload

上傳時同時指定內容類型。

curl -F "content=<達西的身世.txt;type=text/html" https://example.com/upload

上傳文件的和其他參數一起。

curl -F 'file=@"localfile";filename="nameinpost"' example.com/upload

7. 網址通配

cURL 可以實現多個網址的匹配,你可以使用 {} 結合逗號分割來標識使用 url 中的某一段,也可以使用 [] 來表示範圍參數。

# 請求 www.baidu.com 和  pan.baidu.com 和 fanyi.baidu.com
$ curl http://{www,pan,fanyi}.baidu.com
# 虛構網址1-10開頭的baidu.com,然後請求
$ curl http://[1-10].baidu.com
# 虛構網址a-z開頭的baidu.com,然後請求
$ curl http://[a-z].baidu.com

這種方式有時候還是很有用處的,比如說你發現了某個網站的 url 規律。

8. 使用 cookie

請求時使用 -c 參數存儲響應的 cookie,使用 -b 可以在請求時帶上指定 cookie.

$ curl -c wdbyte_cookies http://www.wdbyte.com
$ curl -b wdbyte_cookes http://www.wdbyte.com

總結

以上就是 cURL 的常見用法了,最後告訴你一個小技巧,Chrome、Firefox 等瀏覽器可以直接拷貝請求為 cURL 語句。保存之後下次請求測試非常方便。

參考資料

  1. https://curl.haxx.se/docs/manpage.html

最後的話

文章已經收錄在 Github.com/niumoo/JavaNotes ,歡迎Star和指教。更有一線大廠面試點,Java程序員需要掌握的核心知識等文章,也整理了很多我的文字,歡迎 Star 和完善,希望我們一起變得優秀。

文章有幫助可以點個「」或「分享」,都是支持,我都喜歡!
文章每周持續更新,要實時關注我更新的文章以及分享的乾貨,可以關注「 未讀代碼 」公眾號或者我的博客。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台中搬家公司教你幾個打包小技巧,輕鬆整理裝箱!

還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」

過濾器 和 攔截器 6個區別,別再傻傻分不清了_台中搬家

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

本文收錄在個人博客:www.chengxy-nds.top,技術資料共享,同進步

周末有個小夥伴加我微信,向我請教了一個問題:老哥,過濾器 (Filter) 和 攔截器 (Interceptor) 有啥區別啊? 聽到題目我的第一感覺就是:簡單

畢竟這兩種工具開發中用到的頻率都相當高,應用起來也是比較簡單的,可當我準備回復他的時候,竟然不知道從哪說起,支支吾吾了半天,場面炒雞尷尬有木有,工作這麼久一個基礎問題答成這樣,丟了大人了。

平時覺得簡單的知識點,但通常都不會太關注細節,一旦被別人問起來,反倒說不出個所以然來。

歸根結底,還是對這些知識了解的不夠,一直停留在會用的階段,以至於現在一看就會一說就廢!這是典型基礎不紮實的表現,哎·~,其實我也就是個虛胖!

知恥而後勇,下邊結合實踐,更直觀的來感受一下兩者到底有什麼不同?

準備環境

我們在項目中同時配置 攔截器過濾器

1、過濾器 (Filter)

過濾器的配置比較簡單,直接實現Filter 接口即可,也可以通過@WebFilter註解實現對特定URL攔截,看到Filter 接口中定義了三個方法。

  • init() :該方法在容器啟動初始化過濾器時被調用,它在 Filter 的整個生命周期只會被調用一次。注意:這個方法必須執行成功,否則過濾器會不起作用。

  • doFilter() :容器中的每一次請求都會調用該方法, FilterChain 用來調用下一個過濾器 Filter

  • destroy(): 當容器銷毀 過濾器實例時調用該方法,一般在方法中銷毀或關閉資源,在過濾器 Filter 的整個生命周期也只會被調用一次

@Component
public class MyFilter implements Filter {
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        System.out.println("Filter 前置");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter 處理中");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {

        System.out.println("Filter 後置");
    }
}

2、攔截器 (Interceptor)

攔截器它是鏈式調用,一個應用中可以同時存在多個攔截器Interceptor, 一個請求也可以觸發多個攔截器 ,而每個攔截器的調用會依據它的聲明順序依次執行。

首先編寫一個簡單的攔截器處理類,請求的攔截是通過HandlerInterceptor 來實現,看到HandlerInterceptor 接口中也定義了三個方法。

  • preHandle() :這個方法將在請求處理之前進行調用。注意:如果該方法的返回值為false ,將視為當前請求結束,不僅自身的攔截器會失效,還會導致其他的攔截器也不再執行。

  • postHandle():只有在 preHandle() 方法返回值為true 時才會執行。會在Controller 中的方法調用之後,DispatcherServlet 返回渲染視圖之前被調用。 有意思的是postHandle() 方法被調用的順序跟 preHandle() 是相反的,先聲明的攔截器 preHandle() 方法先執行,而postHandle()方法反而會後執行。

  • afterCompletion():只有在 preHandle() 方法返回值為true 時才會執行。在整個請求結束之後, DispatcherServlet 渲染了對應的視圖之後執行。

@Component
public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("Interceptor 前置");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

        System.out.println("Interceptor 處理中");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        System.out.println("Interceptor 後置");
    }
}

將自定義好的攔截器處理類進行註冊,並通過addPathPatternsexcludePathPatterns等屬性設置需要攔截或需要排除的 URL

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**");
    }
}

我們不一樣

過濾器 和 攔截器 均體現了AOP的編程思想,都可以實現諸如日誌記錄、登錄鑒權等功能,但二者的不同點也是比較多的,接下來一一說明。

1、實現原理不同

過濾器和攔截器 底層實現方式大不相同,過濾器 是基於函數回調的,攔截器 則是基於Java的反射機制(動態代理)實現的。

這裏重點說下過濾器!

在我們自定義的過濾器中都會實現一個 doFilter()方法,這個方法有一個FilterChain 參數,而實際上它是一個回調接口。ApplicationFilterChain是它的實現類, 這個實現類內部也有一個 doFilter() 方法就是回調方法。

public interface FilterChain {
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain裏面能拿到我們自定義的xxxFilter類,在其內部回調方法doFilter()里調用各個自定義xxxFilter過濾器,並執行 doFilter() 方法。

public final class ApplicationFilterChain implements FilterChain {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) {
            ...//省略
            internalDoFilter(request,response);
    }
 
    private void internalDoFilter(ServletRequest request, ServletResponse response){
    if (pos < n) {
            //獲取第pos個filter    
            ApplicationFilterConfig filterConfig = filters[pos++];        
            Filter filter = filterConfig.getFilter();
            ...
            filter.doFilter(request, response, this);
        }
    }
 
}

而每個xxxFilter 會先執行自身的 doFilter() 過濾邏輯,最後在執行結束前會執行filterChain.doFilter(servletRequest, servletResponse),也就是回調ApplicationFilterChaindoFilter() 方法,以此循環執行實現函數回調。

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        filterChain.doFilter(servletRequest, servletResponse);
    }

2、使用範圍不同

我們看到過濾器 實現的是 javax.servlet.Filter 接口,而這個接口是在Servlet規範中定義的,也就是說過濾器Filter 的使用要依賴於Tomcat等容器,導致它只能在web程序中使用。

而攔截器(Interceptor) 它是一個Spring組件,並由Spring容器管理,並不依賴Tomcat等容器,是可以單獨使用的。不僅能應用在web程序中,也可以用於ApplicationSwing等程序中。

3、觸發時機不同

過濾器攔截器的觸發時機也不同,我們看下邊這張圖。

台中搬家遵守搬運三大原則,讓您的家具不再被破壞!

台中搬家公司推薦超過30年經驗,首選台中大展搬家

過濾器Filter是在請求進入容器后,但在進入servlet之前進行預處理,請求結束是在servlet處理完以後。

攔截器 Interceptor 是在請求進入servlet后,在進入Controller之前進行預處理的,Controller 中渲染了對應的視圖之後請求結束。

4、攔截的請求範圍不同

在上邊我們已經同時配置了過濾器和攔截器,再建一個Controller接收請求測試一下。

@Controller
@RequestMapping()
public class Test {

    @RequestMapping("/test1")
    @ResponseBody
    public String test1(String a) {
        System.out.println("我是controller");
        return null;
    }
}

項目啟動過程中發現,過濾器的init()方法,隨着容器的啟動進行了初始化。

此時瀏覽器發送請求,F12 看到居然有兩個請求,一個是我們自定義的 Controller 請求,另一個是訪問靜態圖標資源的請求。

看到控制台的打印日誌如下:

執行順序 :Filter 處理中 -> Interceptor 前置 -> 我是controller -> Interceptor 處理中 -> Interceptor 處理后

Filter 處理中
Interceptor 前置
Interceptor 處理中
Interceptor 後置
Filter 處理中

過濾器Filter執行了兩次,攔截器Interceptor只執行了一次。這是因為過濾器幾乎可以對所有進入容器的請求起作用,而攔截器只會對Controller中請求或訪問static目錄下的資源請求起作用。

5、注入Bean情況不同

在實際的業務場景中,應用到過濾器或攔截器,為處理業務邏輯難免會引入一些service服務。

下邊我們分別在過濾器和攔截器中都注入service,看看有什麼不同?

@Component
public class TestServiceImpl implements TestService {

    @Override
    public void a() {
        System.out.println("我是方法A");
    }
}

過濾器中注入service,發起請求測試一下 ,日誌正常打印出“我是方法A”

@Autowired
    private TestService testService;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("Filter 處理中");
        testService.a();
        filterChain.doFilter(servletRequest, servletResponse);
    }
Filter 處理中
我是方法A
Interceptor 前置
我是controller
Interceptor 處理中
Interceptor 後置

在攔截器中注入service,發起請求測試一下 ,竟然TM的報錯了,debug跟一下發現注入的service怎麼是Null啊?

這是因為加載順序導致的問題,攔截器加載的時間點在springcontext之前,而Bean又是由spring進行管理。

攔截器:老子今天要進洞房;
Spring:兄弟別鬧,你媳婦我還沒生出來呢!

解決方案也很簡單,我們在註冊攔截器之前,先將Interceptor 手動進行注入。注意:在registry.addInterceptor()註冊的是getMyInterceptor() 實例。

@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Bean
    public MyInterceptor getMyInterceptor(){
        System.out.println("注入了MyInterceptor");
        return new MyInterceptor();
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {

        registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");
    }
}

6、控制執行順序不同

實際開發過程中,會出現多個過濾器或攔截器同時存在的情況,不過,有時我們希望某個過濾器或攔截器能優先執行,就涉及到它們的執行順序。

過濾器用@Order註解控制執行順序,通過@Order控制過濾器的級別,值越小級別越高越先執行。

@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class MyFilter2 implements Filter {

攔截器默認的執行順序,就是它的註冊順序,也可以通過Order手動設置控制,值越小越先執行。

 @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/**").order(2);
        registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/**").order(1);
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").order(3);
    }

看到輸出結果發現,先聲明的攔截器 preHandle() 方法先執行,而postHandle()方法反而會後執行。

postHandle() 方法被調用的順序跟 preHandle() 居然是相反的!如果實際開發中嚴格要求執行順序,那就需要特別注意這一點。

Interceptor1 前置
Interceptor2 前置
Interceptor 前置
我是controller
Interceptor 處理中
Interceptor2 處理中
Interceptor1 處理中
Interceptor 後置
Interceptor2 處理后
Interceptor1 處理后

那為什麼會這樣呢? 得到答案就只能看源碼了,我們要知道controller 中所有的請求都要經過核心組件DispatcherServlet路由,都會執行它的 doDispatch() 方法,而攔截器postHandle()preHandle()方法便是在其中調用的。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    
        try {
         ...........
            try {
           
                // 獲取可以執行當前Handler的適配器
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                // 注意: 執行Interceptor中PreHandle()方法
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // 注意:執行Handle【包括我們的業務邏輯,當拋出異常時會被Try、catch到】
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                applyDefaultViewName(processedRequest, mv);

                // 注意:執行Interceptor中PostHandle 方法【拋出異常時無法執行】
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
        }
        ...........
    }

看看兩個方法applyPreHandle()applyPostHandle()具體是如何被調用的,就明白為什麼postHandle()preHandle() 執行順序是相反的了。

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if(!ObjectUtils.isEmpty(interceptors)) {
            for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                HandlerInterceptor interceptor = interceptors[i];
                if(!interceptor.preHandle(request, response, this.handler)) {
                    this.triggerAfterCompletion(request, response, (Exception)null);
                    return false;
                }
            }
        }

        return true;
    }
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        HandlerInterceptor[] interceptors = this.getInterceptors();
        if(!ObjectUtils.isEmpty(interceptors)) {
            for(int i = interceptors.length - 1; i >= 0; --i) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

發現兩個方法中在調用攔截器數組 HandlerInterceptor[] 時,循環的順序竟然是相反的。。。,導致postHandle()preHandle() 方法執行的順序相反。

總結

我相信大部分人都能熟練使用濾器和攔截器,但兩者的差別還是需要多了解下,不然開發中使用不當,時不時就會出現奇奇怪怪的問題,以上內容比較簡單,新手學習老鳥複習,有遺漏的地方還望大家积極補充,如有理解錯誤之處,還望不吝賜教。

原創不易,燃燒秀髮輸出內容

整理了幾百本各類技術电子書, 送給小夥伴們, 我的同名公眾號自行領取。和一些小夥伴們建了一個技術交流群,一起探討技術、分享技術資料,旨在共同學習進步,如果感興趣就加入我們吧!

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台中搬家公司費用怎麼算?

擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司

掄牆鞭死5歲童 養母求處囚終身_網頁設計公司

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

新聞出處: 蘋果日報   記者:孫友廉、黃哲民

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。



毆打虐待養子致死的樊女,遭求處無期徒刑。資料照片

新北市樊姓女子因曾凌虐年幼養子,今 年5月,遭法院判刑確定,不料,今年9月,她竟再持水管鞭打5歲養子,更腳踹、手掐養子下體,還抓養子頭去撞牆,致養子傷重死亡。板橋地檢署痛斥樊女手段 殘忍,虐待成性,昨依殺人罪起訴,求處無期徒刑,也請法院繼續羈押獲准。

曾遭判刑仍未悔悟

33 歲的樊女與夫因無法生育,陸續領養1子1女,前年7月起,樊女便常以年僅3歲的養子隨地便溺、不受管教等理由,多次毆打養子,造成他身體、生殖器等多處受 傷;8月10日,更打傷養子頭部,造成長約11公分的撕裂傷,今年5月才遭台灣高等法院依傷害罪判刑4月,得易科罰金12萬元,緩刑5年,緩刑期間交付保 護管束確定。

不料樊女仍未悔悟,今年9月14日,在觀護人探視輔導3天後,竟再持水管鞭打養子,還手捏下體,腳踹胸腹,將養子推倒在地,再抓養子 頭去撞牆;樊女見養子沒反應也未送醫,直到丈夫下班發現,連忙開車載養子、樊女,前去警局報案,樊夫到警局便大喊:「誰會CPR?趕快救救我兒子!」但養 子已氣絕身亡。

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

俄童生吞42個磁鐵 嚇壞母親_如何寫文案

※別再煩惱如何寫文案,掌握八大原則!

什麼是銷售文案服務?A就是幫你撰寫適合的廣告文案。當您需要販售商品、宣傳活動、建立個人品牌,撰寫廣告文案都是必須的工作。

新聞出處: 蘋果日報  

俄羅斯一名1歲又4個月大的男童,在上周二被母親發現生吞42個磁鐵,緊急送醫後,醫師從男童體內取出磁鐵,目前男童恢復狀況良好。

據了解,日前男童的母親發現,貼在冰箱上的磁鐵不翼而飛,

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

擁有後台管理系統的網站,將擁有強大的資料管理與更新功能,幫助您隨時新增網站的內容並節省網站開發的成本。

懷疑是兒子為了好玩,將磁鐵拿走。這名母親的猜測無誤,磁鐵確實被男童拿走,但母親之後驚覺男童竟把磁鐵吃下肚,將男童送醫。醫師表示,他們從男童肚裡取出42個磁鐵。


俄國1歲4個月大男童生吞42個磁鐵,嚇壞母親。翻自網路

醫師也說,這或許是他執業以來遇到的「紀錄」,也呼籲家長注意將小東西放在兒童拿不到的地方。

※教你寫出一流的銷售文案?

銷售文案是什麼?A文案是廣告用的文字。舉凡任何宣傳、行銷、販賣商品時所用到的文字都是文案。在網路時代,文案成為行銷中最重要的宣傳方式,好的文案可節省大量宣傳資源,達成行銷目的。

3歲男童掉入15米深井底 鑽繩套成功自救_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

新聞出處:北京新浪網    





放大圖
看更多圖片

  本報訊(記者 陳海峰 通訊員 馬世華 文圖) 本報商丘訊 柘城縣梁庄鄉一名3歲男孩在捉蝴蝶時,不慎掉入15米深的機井中。由於井口直徑僅40厘米,救援人員根本無法下井。消防官兵衹好將救援繩子打結,慢慢放入井內,現場指導落井孩子自己操作,半個小時後,孩子被救上來。經醫生檢查,小孩衹受了些擦傷,無生命危險。

  3歲娃掉入15米深機井里

  3月11日下午,提起兒子掉入井里的那一幕,柘城縣梁庄鄉的劉先生仍然心有余悸。

  據他介紹,3月8日下午,兒子和鄰居的一個同齡孩子出去玩耍,誰知,一會兒兩人便不見了蹤影。正在家人尋找時,鄰居的孩子跑回來說他兒子在捉蝴蝶時,掉進了麥地的井里。

  “我一路找一路喊我兒子名字,聽到他的哭聲,立即趕過去,看到兒子正在井下,水淹到孩子胸口處。”劉先生說,他趕緊撥打了119。

  接到求助電話後,柘城縣消防官兵迅速趕赴現場。

  消防員在現場看到,該機井直徑約40厘米,深約15米,水面距離地面約14米。借著燈光觀察,可見男孩上半身卡在井下水面之上,情況萬分危急。

  消防員指導協助

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

  孩子自救成功

  消防官兵迅速利用壓縮氣瓶向井底輸送新鮮空氣,並對落井小孩持續喊話:“小朋友,不要怕,叔叔馬上救妳上來。”

  由於井口太窄,救援人員無法下井。於是,救援人員制訂了三個救援方案:一是利用井下救援鉤進行救援﹔二是利用結繩法打套進行救援﹔三是利用挖掘機挖土救援。

  由於孩子被卡在井壁內,救援器材無法展開,第一個救援方案未能成功﹔此時,救援人員調來了一台大型挖掘機,第三個方案和第二個方案同時進行。

  救援人員將繩索打個套,慢慢放入井內,接近落井小孩,同時向其喊話:“小朋友,不要害怕,叔叔馬上就救妳上來,妳配合一下,把妳的雙手合在一塊,伸入繩圈,然後抓住繩圈上面的繩結。小朋友,不要害怕,慢慢來,妳馬上就能上來了。”

  聽到消防人員的喊話後,小孩將手套入繩套中,救援人員慢慢地收緊繩子。但剛向上提升約兩米,小孩的頭部被井壁突出部分卡住,無法繼續上升。哇哇的哭聲又從井底傳出。

  “小朋友,不要怕,妳馬上就能出來了,請按照叔叔說的做,把妳的頭慢慢地向前趴,向妳手臂的方向……”消防隊員小心翼翼地拉著繩子,耐心地向孩子喊話。

  聽到喊話,小孩的情緒好轉,並按照消防隊員的方法將頭慢慢靠近自己的手臂,經過一番努力,落井小孩終於通過了那段狹窄的井壁,慢慢地被拉了上來。

  劉先生夫婦看到孩子被救了上來,一把抱住孩子,哭了起來。經醫生檢查,孩子的臉部和右腳部有些擦傷,生命體征完好。

(原標題:真能!3歲娃15米深井底鑽繩套自救)

詳全文 3歲男童掉入15米深井底 鑽繩套成功自救-兩岸新聞-新浪新聞中心 http://news.sina.com.tw/article/20130312/9135110.html

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌