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 本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

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

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

過濾器 和 攔截器 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星評價的搬家公司

OkHttp,一次無奈的使用_網頁設計公司

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

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

一次使用OKHTTP的心痛歷程

最近由於一些不得已的原因,接觸到了OKHttp,說起來也挺Dan疼的,之前同事將生產附件上傳地址配置成了測試地址,還好數量不多,沒有造成太大的影響,況且的是這位同事又離職了,當時只能在心中
默默的問候了他N遍,當然問候完了之後,也不得不繼續數據同步的工作。

OKHTTP官方地址:okHttp

本文源地址:一次使用OKHTTP的心痛歷程

介紹

由於OkHttp官網的介紹十分詳細,這裏只能貼上一段翻譯過後的introduce:

HTTP是現代應用網絡的一種方式。這就是我們交換數據和媒體的方式。高效地使用HTTP可以讓你的東西更快地加載並節省帶寬。

OkHttp是一個高效的Http客戶端,在默認的情況下:

  • HTTP / 2支持允許對同一主機的所有請求共享一個套接字。
  • 連接池可減少請求延遲(如果HTTP / 2不可用)。
  • 透明的GZIP縮小了下載大小。
  • 響應緩存可以完全避免網絡重複請求。

不過在我使用下來,OkHttp比 apache-http 好用太多,層次結構較直觀。

使用場景

本次場景是將上傳到測試環境的文件信息,下載到本地,然後再上傳到生產環境。

解決過程如下:

  • 將錯誤數據從數據庫表中粘貼到本地新建的一個Excel文件中。(畢竟直接連接數據庫風險更大)

  • 讀取Excel內的信息,獲取文件地址。

  • 請求文件地址,獲取到流文件信息。

  • 拿到流文件信息,拼接上傳數據,上傳到新的生產環境中。

  • 上傳完成后,獲取到生產環境文件地址。

  • 獲取到生產文件地址的同時,生成更新的SQL語句。

  • 到數據庫中執行SQL語句。

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

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

使用過程

本次使用沒有搭建新的工程,直接再 src/test/java 目錄下新建一個Java類。

引入OKHttp的依賴:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.3.1</version>
</dependency>

在引入了 okhttp 的jar包后,基本上就可以開始隨心所欲的進行自己任意喪心病狂的Http請求了。

比如,它直接同步和異步的請求:

同步GET

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://publicobject.com/helloworld.txt")
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      Headers responseHeaders = response.headers();
      for (int i = 0; i < responseHeaders.size(); i++) {
        System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
      }

      System.out.println(response.body().string());
    }
  }

異步GET

 private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("http://publicobject.com/helloworld.txt")
        .build();

    client.newCall(request).enqueue(new Callback() {
      @Override public void onFailure(Call call, IOException e) {
        e.printStackTrace();
      }

      @Override public void onResponse(Call call, Response response) throws IOException {
        try (ResponseBody responseBody = response.body()) {
          if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

          Headers responseHeaders = response.headers();
          for (int i = 0, size = responseHeaders.size(); i < size; i++) {
            System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
          }

          System.out.println(responseBody.string());
        }
      }
    });
  }

Header信息

private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    Request request = new Request.Builder()
        .url("https://api.github.com/repos/square/okhttp/issues")
        .header("User-Agent", "OkHttp Headers.java")
        .addHeader("Accept", "application/json; q=0.5")
        .addHeader("Accept", "application/vnd.github.v3+json")
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println("Server: " + response.header("Server"));
      System.out.println("Date: " + response.header("Date"));
      System.out.println("Vary: " + response.headers("Vary"));
    }
  }

POST請求流信息

public static final MediaType MEDIA_TYPE_MARKDOWN
      = MediaType.parse("text/x-markdown; charset=utf-8");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    RequestBody requestBody = new RequestBody() {
      @Override public MediaType contentType() {
        return MEDIA_TYPE_MARKDOWN;
      }

      @Override public void writeTo(BufferedSink sink) throws IOException {
        sink.writeUtf8("Numbers\n");
        sink.writeUtf8("-------\n");
        for (int i = 2; i <= 997; i++) {
          sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
        }
      }

      private String factor(int n) {
        for (int i = 2; i < n; i++) {
          int x = n / i;
          if (x * i == n) return factor(x) + " × " + i;
        }
        return Integer.toString(n);
      }
    };

    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println(response.body().string());
    }
  }

POST請求File信息

  public static final MediaType MEDIA_TYPE_MARKDOWN
      = MediaType.parse("text/x-markdown; charset=utf-8");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    File file = new File("README.md");

    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println(response.body().string());
    }
  }

Post表單提交

 private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    RequestBody formBody = new FormBody.Builder()
        .add("search", "Jurassic Park")
        .build();
    Request request = new Request.Builder()
        .url("https://en.wikipedia.org/w/index.php")
        .post(formBody)
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println(response.body().string());
    }
  }

POST多個Body請求

  /**
   * The imgur client ID for OkHttp recipes. If you're using imgur for anything other than running
   * these examples, please request your own client ID! https://api.imgur.com/oauth2
   */
  private static final String IMGUR_CLIENT_ID = "...";
  private static final MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image
    RequestBody requestBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("title", "Square Logo")
        .addFormDataPart("image", "logo-square.png",
            RequestBody.create(MEDIA_TYPE_PNG, new File("website/static/logo-square.png")))
        .build();

    Request request = new Request.Builder()
        .header("Authorization", "Client-ID " + IMGUR_CLIENT_ID)
        .url("https://api.imgur.com/3/image")
        .post(requestBody)
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

      System.out.println(response.body().string());
    }
  }

因為使用過程中大多數都是按照官網的例子來進行,所以這次使用的代碼是類似於官方提供的例子,當然也是不太好意思貼出來,哈哈。

總結

OkHttp算得上是相見恨晚,之前一遍一遍寫 apache-http 的時候就覺得 apche 有點冗餘,就是想有一個輕量級的,比較好上手,容易懂的http-client,不過現在接觸到了 okhttp,還是得感謝那位配錯地址的兄弟。

以上更多請求例子可以訪問:OKhttp-Request-example

參考資料:

OkHttp.io

OKhttp-Request-example

OKHttp-Github

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

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

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

7.5-15萬不買日系車 上班族首選車型顏值高有格調!_網頁設計公司

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

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

內飾運動感沒有那麼強烈,整體比較中規中矩,不過,配色上沒有那麼沉悶。福克斯有1。0T 1。5T 1。6L三種動力車型選擇,三種車型配置相差並不算太大,都標配了ESp,剎車輔助,牽引力控制等的配置,每一款動力的車型低配和次低配舒適性的配置稍少了一些,但對於日常使用而言,影響並不大。

如今路上的車輛越來越多,塞車,找不到停車位,已經是習以為常的時。因為這樣,現在不少人會選擇“體型”較小的車型,這樣在路上行駛或者在塞車擠位的時候都比較輕鬆。對於一般的上班族而言,下面這些車型就適合。

上汽大眾-pOLO

指導價:7.59-14.69萬

pOLO的外觀大家也再熟悉不過了,大眾臉配上小“體型”,有一種別樣的規矩感。內飾造型同樣是大眾風,但鋼琴烤漆高亮度面板和鍍鉻飾條,稍微的提升了些檔次感,布局也以實用為主。

pOLO有1.4L,1.6L以及1.4T車型選擇,對於一般用車,1.4T車型的選擇性較低。1.4L車型除了頂配之外都沒有配備ESp,剎車輔助,牽引力控制,這方便比較不就到,舒適配置表現中下,畢竟是8萬的大眾車。1.6L車型低配和次低配車型安全配置較低,舒適性配置比1.4L車型多了幾個,例如,電動天窗,定速巡航等,頂配和次頂配車型有配備ESp,剎車輔助,牽引力控制,舒適性配置也比較齊全。另外,1.4L車型的自動風尚型可以選裝ESp,剎車輔助,牽引力控制。

長安福特-福克斯

指導價:9.98-16.58萬

馬丁臉有較強烈的視覺感,整體的設計運動型較強,對於喜歡有點激情的上班族來說,很適合。內飾運動感沒有那麼強烈,整體比較中規中矩,不過,配色上沒有那麼沉悶。

福克斯有1.0T 1.5T 1.6L三種動力車型選擇,

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

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

三種車型配置相差並不算太大,都標配了ESp,剎車輔助,牽引力控制等的配置,每一款動力的車型低配和次低配舒適性的配置稍少了一些,但對於日常使用而言,影響並不大。中配車型配置比較齊全,日常使用很足夠,例如,電動天窗,多功能方向盤,后駐車雷達等都有配備。而頂配車型還配備了併線輔助,車道偏離系統,但價格較貴,日常使用,選擇中低配車型就足夠了。

東風標緻-標緻308S

指導價:11.27-17.97萬

不一樣的風情,這是308S給人的第一眼感覺,濃濃的法系味道。內飾顯得比較簡約,但做工依然保持了法系的精緻,看起很有質感,物理按鍵被替代成了觸碰式的,這對操作的實用性有一定的減少。

308S有1.2T 1.6L 1.6T三種動力車型車選擇,1.2T和1.6L的頂配車型配置較為齊全一些,但有些奇怪的是,全系都有配備ESp,剎車輔助,上坡輔助,就是沒有配備牽引力控制,頂配有配備全景天窗但是全系都沒有電動天窗,這算是法系的獨特的風格?中低配車型雖然配置較少,但對於日常使用也還是足夠的,只要你對配置要求不高的話。1.6T車型整體配置算得上齊全,有配備牽引力控制,但還是沒有電動天窗,其他舒適性配置算得上豐富,不過價格就貴了不少,不太推薦。

總結:斯文派的pOLO,激情派的福克斯,時尚派的標誌308S,三種不同風格之選。在價格上,pOLO算上優惠,最低配裸車價可以去到6萬多,而福克斯和308S價格稍微貴一些,但配置上會好很多。總體而言,福克斯各方面比較均衡,價格不高也不低,配置也一樣,對於現在人選車的“理念”而言,比較適合。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

低配高配相差甚遠 怎樣花最少的錢享受到高配置?_網頁設計公司

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

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

而高配車雖有各種高科技配置,但也帶來了高額的購車成本。所以,如果選了低配車而又不滿意,還有什麼好辦法可以補救下。總結:對於低配車加裝配置,可能在成本上比原高配車要佔優,但要注意的是,無論後期加裝的配置有多先進,總體上跟原高配車的體驗還是會有所不同。

買車除了關心汽車的三大件,配置高低也是必不可少的一項指標。但問題是,真到了選擇高配車和低配車的時候,你會怎麼選?現在的低配車配置寒酸,見不得人,但購買門檻低。而高配車雖有各種高科技配置,但也帶來了高額的購車成本。所以,

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

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

如果選了低配車而又不滿意,還有什麼好辦法可以補救下?

總結:對於低配車加裝配置,可能在成本上比原高配車要佔優,但要注意的是,無論後期加裝的配置有多先進,總體上跟原高配車的體驗還是會有所不同。因此,在看來,後期加裝配置也要適可而止,要跟自己實際需求掛鈎,切勿盲目貪心的強行增加配置,特別是一些高級配置,更是要慎之又慎,不然,花點錢倒是小事,搞壞了車子才是悲劇。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

最便宜的中型車 13萬國貨或韓系你選誰?_網頁設計公司

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

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

動力對比B70搭載兩款發動機。2。0L自然吸氣發動機、1。8T渦輪增壓發動機,最大功率108千瓦、137千瓦,最大扭矩184牛米、235牛米,傳動系統方面,配備的是6擋手動和6擋手自一體,在參數上,B70的整套動力總成,動力還是比較充裕的,無論是買手動還是手自一體車型,穩定性都比較高。

可能在一些朋友眼裡,B級車一直都是20萬出頭,但是你終於不用去湊20萬去買一款B級車了,只要15萬左右的預算就可以買到一款B級車了,而且配置高,顏值高!最近編者的朋友也是握着15W左右的預算想買B級車,就看中了名圖和奔騰B70,問編者怎麼選,下面,就讓我們一起來看看這兩輛車之間如何選擇。

北京現代-名圖

指導價:12.98-17.68萬

一汽奔騰-奔騰B70

指導價:9.98-14.98萬

外觀對比

B70整體延續了家族化的設計風格,以往成熟穩重的造型被一套時尚動感的設計所取代,車身的線條比較圓滑,尾部方面設計簡潔大方,B70採用了雙邊共兩出的排氣管,並配鍍鉻裝飾條,整體視覺感官非常精緻。

名圖在外觀上,看起來並沒有B70那麼運動時尚,而是另外一種商務端莊的范,視覺效果並沒有太大的衝擊,車側與車尾造型之間比較簡潔,流暢,保險杠下緣黑色的塑料處理加上單邊雙出的排氣管,也為該車在穩重之餘增添一絲活力。

內飾對比

B70整體還是走運動時尚路線,中控台的“開口”設計就有些另類,顯得過於浮夸了,但整體的設計還是比較簡潔的,深黑色的內飾配上紅線縫製,更加突顯運動的氛圍。中控台也使用了軟質材料,整體的做工用料還是不錯的。在空間方面,B70還是要比名圖寬敞不少,無論是前排還是後排的的腿部空間的余量還是很大的。在長途乘坐感受上,會比名圖要舒服。

名圖的內飾,比B70的內飾氛圍要高級很多,平直式的中控布局,

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

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

還有大面積的木紋裝飾板點綴,所營造的效果更加沉穩,在儲物空間方面,名圖做的相當到位,手機、錢包。水瓶都能找到放的儲物空間,非常好用。在空間方面,頭部空間比較局促,但是在腿部空間表現相當不錯,翹個二郎腿,都沒什麼問題,符合B級車的水準。

動力對比

B70搭載兩款發動機;2.0L自然吸氣發動機、1.8T渦輪增壓發動機,最大功率108千瓦、137千瓦,最大扭矩184牛米、235牛米,傳動系統方面,配備的是6擋手動和6擋手自一體,在參數上,B70的整套動力總成,動力還是比較充裕的,無論是買手動還是手自一體車型,穩定性都比較高。底盤對路面細微的震動傳遞清晰,整個底盤的調校比較硬朗、偏運動。

名圖搭載了1.8L.2.0L的自然吸氣發動機,1.6T渦輪增壓發動機,最大功率105千瓦、114千瓦、128.7千瓦;最大扭矩176牛米、192牛米、265牛米,在傳動系統方面配備了6擋手動、6擋手自一體、7擋雙離合,可供消費者的選擇很多,就看自己的需求了,在動力上,名圖並不會比B70差,名圖在懸挂和底盤調教上更偏重舒適。對路面的顛簸、起伏路面過濾得更為徹底,無論是前後排的乘坐舒適性都非常不錯。

編者點評:

奔騰B70雖然是自主品牌,但並不會比合資品牌差,而且整體的做工、動力都有很大的提升,性價比也特別高,而名圖呢,可圈可點,整體性也還是不錯,但是看起來商務氣息特別濃,缺乏時尚感,和B70相比,它根本就沒有性價比可談,所以我更推薦奔騰B70,B70更加的親民,喜歡與否就看自己的選擇。汽車圈裡還有這樣的一句話“買韓系車,還不如買自主品牌”。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

Google 宣布將推出用相機鏡頭測量心率、呼吸的健康功能

行動裝置已經是全世界人們不可缺少的日常工具,從最基本的互相聯絡、拍照到獲取資訊等都可透過它來解決,隨著手機上所搭載的技術與感測器越來越進步、精確,所能運用的方面也越來越多元,Google 日前宣布將推出用手機鏡頭來測量心率與呼吸的健康功能,幫助用戶掌握身體健康狀態。

Google 宣布將推出用相機鏡頭測量心率、呼吸的健康功能

心率與呼吸速率是想向通成用來評估基礎健康的生命體征,在過去我們習慣用搭配的穿戴裝置(智慧手環、手錶)等進行監控,從下個月開始,Google Fit 將允許用戶僅透過現在已經是手機上標準配備的相機鏡頭來測量用戶的心率與呼吸速率,這些功能將會率先於 Pixel 手機上的 Google Fit 中提供,未來計劃會擴展到更多 Android 行動裝置上。

如果想要測量呼吸速率,只需將自拍鏡頭對準自己的頭與上軀幹部位,並且保持正常呼吸的狀態;如果想要測量心率,則只需將手指放到後置主鏡頭上即可。其原理在於現在感測器與視覺感應的進步,讓智慧型手機上的攝影機能夠以像素等級來追蹤非常細微的物理訊號,像是透過胸部運動來測量呼吸速率,手指顏色的細微變化來察覺心率等。

雖然這些測量並不是用來作為醫療診斷或評估醫療狀況,但 Google 的出發點是希望能夠讓人們利用 Google Fit 應用程式來追蹤與改善日常健康,測量完成之後,你可以選擇將數據保存在應用程式中,以追蹤隨著時間變化的身體狀況。這兩項功能已經完成初步臨床研究來驗證,即便照明、膚色、年齡不同會對測量帶來考驗,有賴於演算法的進步,還是可以適用於絕大多數人。

您也許會喜歡:

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

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

【其他文章推薦】

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

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

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

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

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

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

疑似 Android 12 的 UI 全新介面設計截圖現身,圖示、通知、Widget 都有改變

離去年 Android 11 發表的時間也快要一年了,沒意外應該這幾個月就有機會看到 Android 12 作業系統,而功能部分先前已經有外媒從開發程式碼中推算,介面設計最近終於也有相關傳聞出現,有人從 Google 早期文件中找到疑似 Android 12 的介面截圖,跟現今 Android 11 可說有蠻大的改變,我個人是蠻喜歡的。

疑似 Android 12 的 UI 全新介面設計截圖現身

根據外媒 XDA-Developers 獲得的消息,稍早有人從 Google 早期文件中提取了 Android 12 新 UI 設計截圖,下圖為新的通知面板,可以看到不再是透明背景,而是改用淺米色替代。每個訊息通知的四個圓角也變更加明顯、且更大,圖示部分也一樣,這也導致能塞入的功能設置數量減少到 4 個:

Android 12 也預計加入跟 iOS 14 一樣的隱私新功能,只要當前有應用程式正使用你手機的相機或麥克風,畫面就會顯示提示,也能點擊它查看是哪一個應用程式:

新的隱私設置頁面,你可以關閉相機、靜音麥克風、管理位置資訊、甚至是停用設備上的感應器等等。不過這似乎只有在啟用 “開發人員選項” 後才會出現:

主畫面的模樣就沒有改變太多:

似乎也加入新的 Widget 小工具功能:

可添加最近的訊息、未接來電或活動狀態的 Widget:

不過好像只有一個大小選擇:

XDA 也補充,他們尚未收到這份完整文件,因此還無法 100% 驗證這些圖片的真實性,不過可以確定的是,來源相當值得信賴。

功能方面,先前 9to5Google 也整理可能會有這 3 項:

  • App Pairs:改進版分割螢幕,讓用戶能更快將兩個常用應用程式組合一起並使用。
  • Columbus:雙擊手機背面可啟用功能操作。
  • hibernate:休眠未使用的應用程式,壓縮檔案來釋出更多儲存空間。

Android 正式推出時間目前還不知道,不過沒意外應該會落在上半年。

資料來源:XDA-Developers

外媒:這 5 個 iPhone 12 特色,Android 應該要學習與複製

您也許會喜歡:

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

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

【其他文章推薦】

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

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

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

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

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

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

想不到7.5萬起車型開起來比14萬的車還更爽!

38-11。28萬本田飛度有着“知乎神車”的稱號,原因10萬以內沒能找到一輛這樣低油耗、加速快以及高保值率的合資車。它使用的是1。5L地球夢發動機,最大功率96千瓦,配合5MT手動變速箱,可以實現9s以內的百公里加速時間,另外還有CVT變速箱可以選擇。

前言

“才六七萬錢的車,能開就行了,還要什麼操控樂趣?”,相信這句話是不少人都聽到過的,認為低價位的汽車都是比較無聊的,但是有沒有想過有些六七萬起售的汽車能給到你超越價格的樂趣,甚至要比貴了一倍價錢的車型還要好玩?

小型車,其實是一個被忽略的市場,在國產緊湊型轎車以及小型SUV的轟炸下,合資小型車的市場份額被逐漸蠶食。以前那種合資小型車百花齊放的景象已經看不到了,前些年年輕人都追求的是這種有着絕佳的操控樂趣小車。

它們都有着小巧的車身,在車流中可以非常靈活地穿梭;有着精準的操控,坐在車內有着一種人車合一的感覺;有着極低的重心,即使在山道也能有着較佳的車身姿態。有着類似卡丁車的操控樂趣,而且還有着較高的改裝潛力。

上汽大眾-pOLO

官方指導價:7.59-14.69萬

作為德系的代表,大眾pOLO有着極高的造詣,小巧的車身配合精準的操控,這輛小型車有着超高的駕駛樂趣,較高速度過彎都能有着一個極佳的姿態。所以在不少車隊甚至是大眾官方都是將其作為賽車車型的首選,價格低操控好而且改裝潛力大。

不過對於家庭用戶來說,後排空間就相對局促。動力方面有着1.4L以及1.6L自然吸氣發動機可以選擇,變速箱則是5MT以及6AT變速箱可以選擇,不過更推薦的是5MT,傳動效率高動力佳,而且檔位清晰,離合容易控制,上手難度低。

廣汽本田-飛度

官方指導價:7.38-11.28萬

本田飛度有着“知乎神車”的稱號,原因10萬以內沒能找到一輛這樣低油耗、加速快以及高保值率的合資車。它使用的是1.5L地球夢發動機,最大功率96千瓦,配合5MT手動變速箱,可以實現9s以內的百公里加速時間,另外還有CVT變速箱可以選擇。

它還有着極其優秀的車廂空間,完全不亞於某些合資緊湊型轎車,加上低油耗的特點非常適合家庭使用。動力強以及手感極好的手動變速箱,讓它有着超高的加速性能,不過過彎的時候側傾稍微有點大,但幸好可以通過改裝改善。

長安鈴木-雨燕

官方指導價:5.98-8.28萬

鈴木雨燕是之前小型車大熱時的產物,到如今那麼多年都僅僅是對外觀進行小小的修改,所以有着當初那種最佳的駕駛樂趣,不過也是因為這麼多年都沒有進行性能上的改進而為人所詬病。發動機方面有着1.3L以及1.5L兩種排量可以選擇,1.5L自然吸氣發動機最大功率76千瓦,相對弱勢。

但配合5MT手動變速箱操控極佳,加上優秀的底盤表現以及改裝潛力使得它是第三代飛度之前最熱的改裝車,如今在不少賽車場都可以看到它的蹤影。並且對於某些改裝發燒友來說,可以無損改裝進口速翼特的M16A發動機也是重大的優勢,動力輸出更加,高轉有着極其優秀的表現和魅力。

編輯總結:

以上三款汽車都可以說是這個價位中操控最好的代表,甚至比起12萬左右的合資緊湊型轎車還要優秀。價格基本可以在不到7萬可以買到,尤其是大眾pOLO,終端起售價甚至可以在6.5萬左右,非常適合追求駕駛樂趣的年輕人。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

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

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

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

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

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

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

部分Apple Watch S5、SE發生充電故障 蘋果官方宣布免費維修

近日有部分Apple Watch Series 5、Apple Watch SE的使用者回報,當手錶進入「省電模式」後,就沒有辦法充電,蘋果於16日發布最新的watchOS進行修正,同時也表示,如果仍然無法充電的話,請聯繫蘋果進行維修。

↑部分Apple Watch傳出進入省電模式後,無法充電的故障問題。(示意圖/pixabay)

蘋果今日在官方網站上發文,表示有極小部分的Apple Watch Series 5、Apple Watch SE在執行 watchOS 7.2或7.3版本系統時,當進入「省電模式」後,會發生無法充電的問題。宣布在今日發布最新版作業系統watchOS 7.3.1,表示只要更新到此版系統後,就不會再有這樣的狀況。

而蘋果官方表示,建議原本有問題的Apple Watch Series 5、Apple Watch SE,在更新系統後,先將手表放在常用的充電器上「至少等待30分鐘」,如果還是無法充電的話,可以聯繫蘋果官方進行維修。

您也許會喜歡:

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

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

【其他文章推薦】

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

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

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

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

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

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