中國製 TESLA Model Y 上線官網,台灣開賣時間也不遠了?_網頁設計公司

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

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

在2021年的1月1日,中國特斯拉官網突然上架的 TESLA Model Y 的產品頁面,由於中國特斯拉除了 Model X、Model S 與 Model 3 性能版以外已經全面進入中國自製階段(3P也快進入全中國產)而且還可以外銷歐洲,這次的更大的意義在於連 Model Y 也開始全面中國廠生產,另外根據未證實的小道消息指稱,台灣 TESLA Model Y 也可能在今年春天開始在台上市販售。

中國製 TESLA Model Y 上線官網

這次中國特斯拉官網上架的是 Model Y 長續航全輪驅動版與 Performance 高性能版兩種規格,而沒有之前傳言可能更便宜、續航更好的 RWD 版本,兩輛車主要的差異在於輪穀大小(19/20 vs 21吋)、車身重量(1997 vs 2010)、續航(594 vs 480KM WLTP)、最高時速(217 vs 241 KM)與百公里加速(5.1 vs 3.7 秒),電池部分可能採用最近爭議頗大的磷酸鐵鋰電池:

▲圖片來源中國特斯拉。

價格方面,長續航版折合約為台幣146.5萬,高性能版約為159.5萬台幣(超過30萬人民幣無電動車購車補助),都比台灣的 Model 3 SR+ 便宜(中華民國萬萬稅),另外有傳言台灣應該在春天的時候也會開賣由美國進口的 TESLA Model Y,個人不負責猜測價格約在210萬~230萬左右,由於 Model Y 是車身比較寬敞的後掀背車款,比較受到喜歡 SUV 車型的民眾喜愛,預料開賣時應該會有另一波搶購熱潮:

實車在路上也被直擊了:

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

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

Tesla MIC Model Y delivery may start earlier than all we expected. https://t.co/rPMeUvXto2 pic.twitter.com/i0vyyDaFAd

— Vincent (@vincent13031925) January 1, 2021

您也許會喜歡:

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

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

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

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

基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(三)_網頁設計公司

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

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

系列文章

  1. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用 abp cli 搭建項目
  2. 基於 abp vNext 和 .NET Core 開發博客項目 – 給項目瘦身,讓它跑起來
  3. 基於 abp vNext 和 .NET Core 開發博客項目 – 完善與美化,Swagger登場
  4. 基於 abp vNext 和 .NET Core 開發博客項目 – 數據訪問和代碼優先
  5. 基於 abp vNext 和 .NET Core 開發博客項目 – 自定義倉儲之增刪改查
  6. 基於 abp vNext 和 .NET Core 開發博客項目 – 統一規範API,包裝返回模型
  7. 基於 abp vNext 和 .NET Core 開發博客項目 – 再說Swagger,分組、描述、小綠鎖
  8. 基於 abp vNext 和 .NET Core 開發博客項目 – 接入GitHub,用JWT保護你的API
  9. 基於 abp vNext 和 .NET Core 開發博客項目 – 異常處理和日誌記錄
  10. 基於 abp vNext 和 .NET Core 開發博客項目 – 使用Redis緩存數據
  11. 基於 abp vNext 和 .NET Core 開發博客項目 – 集成Hangfire實現定時任務處理
  12. 基於 abp vNext 和 .NET Core 開發博客項目 – 用AutoMapper搞定對象映射
  13. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(一)
  14. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(二)
  15. 基於 abp vNext 和 .NET Core 開發博客項目 – 定時任務最佳實戰(三)
  16. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(一)
  17. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(二)
  18. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(三)
  19. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(四)
  20. 基於 abp vNext 和 .NET Core 開發博客項目 – 博客接口實戰篇(五)
  21. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(一)
  22. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(二)
  23. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(三)
  24. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(四)
  25. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(五)
  26. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(六)
  27. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(七)
  28. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(八)
  29. 基於 abp vNext 和 .NET Core 開發博客項目 – Blazor 實戰系列(九)
  30. 基於 abp vNext 和 .NET Core 開發博客項目 – 終結篇之發布項目

上一篇(https://www.cnblogs.com/meowv/p/12974439.html)完成了全網各大平台的熱點新聞數據的抓取,本篇繼續圍繞抓取完成后的操作做一個提醒。當每次抓取完數據后,自動發送郵件進行提醒。

在開始正題之前還是先玩一玩之前的說到卻沒有用到的一個庫PuppeteerSharp

PuppeteerSharp:Headless Chrome .NET API ,它運用最多的應該是自動化測試和抓取異步加載的網頁數據,更多介紹可以看GitHub:https://github.com/hardkoded/puppeteer-sharp 。

我這裏主要來試試它的異步抓取功能,同時它還能幫我們生成網頁截圖或者PDF。

如果沒有安裝可以先安裝一下,在.BackgroundJobs層安裝PuppeteerSharpInstall-Package PuppeteerSharp

在Jobs文件夾下新建一個PuppeteerTestJob.cs,繼承IBackgroundJob,同樣是在ExecuteAsync()方法中執行操作。

//PuppeteerTestJob.cs
using System;
using System.Threading.Tasks;

namespace Meowv.Blog.BackgroundJobs.Jobs.PuppeteerTest
{
    public class PuppeteerTestJob : IBackgroundJob
    {
        public async Task ExecuteAsync()
        {
            throw new NotImplementedException();
        }
    }
}

使用 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision); 第一次檢測到沒有瀏覽器文件會默認幫我們下載 chromium 瀏覽器。

DownloadAsync(...)可以指定 Chromium 版本,BrowserFetcher.DefaultRevision 下載當前默認最穩定的版本。

然後配置瀏覽器啟動的方式。

using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
    Headless = true,
    Args = new string[] { "--no-sandbox" }
});

感興趣的可以自己看看LaunchOptions有哪些參數,我這裏指定了Headless = true 以無頭模式運行瀏覽器,然後加了一個啟動參數 “–no-sandbox”。針對Linux環境下,如果是運行在 root 權限下,在啟動 Puppeteer 時要添加 “–no-sandbox” 參數,否則 Chromium 會啟動失敗。

我們打開一個異步加載的網頁,然後獲取到頁面加載完后的HTML,以我個人博客中的某個單頁為例:https://meowv.com/wallpaper 。

//PuppeteerTestJob.cs
using PuppeteerSharp;
using System.Threading.Tasks;

namespace Meowv.Blog.BackgroundJobs.Jobs.PuppeteerTest
{
    public class PuppeteerTestJob : IBackgroundJob
    {
        public async Task ExecuteAsync()
        {
            await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);

            using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                Args = new string[] { "--no-sandbox" }
            });

            using var page = await browser.NewPageAsync();

            await page.SetViewportAsync(new ViewPortOptions
            {
                Width = 1920,
                Height = 1080
            });

            var url = "https://meowv.com/wallpaper";
            await page.GoToAsync(url, WaitUntilNavigation.Networkidle0);

            var content = await page.GetContentAsync();
        }
    }
}

page.SetViewportAsync()設置網頁預覽大小,page.GoToAsync()語法打開網頁,WaitUntilNavigation.Networkidle0等待網頁加載完畢,使用page.GetContentAsync()獲取到HTML。

新建擴展方法,調用這個PuppeteerTestJobExecuteAsync()方法,調試看看效果。

HTML已經出來了,此時該幹嘛就幹嘛就可以了。

第一次運行可能會很慢,因為如果你本地不存在 Chromium 是會去幫我們下載的,因為網絡原因可能會下載的很慢,所以推薦大家手動下載。

可以使用淘寶的源:https://npm.taobao.org/mirrors/chromium-browser-snapshots/ 。

要注意的是,下載完成后的解壓的路徑不能出錯,默認下載地址是在啟動目錄下面。

Windows:..\.local-chromium\Win64-706915\chrome-win 、 Linux:../.local-chromium/Linux-706915/chrome-linux

接下來試試生成PDF和保存圖片功能,使用方式也很簡單。

await page.PdfAsync("meowv.pdf",new PdfOptions { });
await page.ScreenshotAsync("meowv.png", new ScreenshotOptions
{
    FullPage = true,
    Type = ScreenshotType.Png
});

這裏只做簡單的展示,page.PdfAsync()直接生成PDF文件,同時還有很多方法可以自己調用page.試試,PdfOptions選項中可以設置各種參數。

page.ScreenshotAsync()保存圖片,ScreenshotOptions中FullPage可以設置保存圖片為全屏模式,圖片格式為Png類型。

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

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

可以看到項目根目錄已經生成了圖片和PDF,感覺去試試吧。

接下里來實現發送郵件的功能。

我這裏發郵件的賬號是用的騰訊企業郵箱,也可以用普通郵箱開通SMTP服務即可。

appsettings.json配置收發郵件的賬號等信息。

//appsettings.json
  "Email": {
    "Host": "smtp.exmail.qq.com",
    "Port": 465,
    "UseSsl": true,
    "From": {
      "Username": "123@meowv.com",
      "Password": "[Password]",
      "Name": "MEOWV.COM",
      "Address": "123@meowv.com"
    },
    "To": [
      {
        "Name": "test1",
        "Address": "test1@meowv.com"
      },
      {
        "Name": "test2",
        "Address": "test2@meowv.com"
      }
    ]
  }

然後再AppSettings中讀取配置的項。

//AppSettings.cs
public static class Email
{
    /// <summary>
    /// Host
    /// </summary>
    public static string Host => _config["Email:Host"];

    /// <summary>
    /// Port
    /// </summary>
    public static int Port => Convert.ToInt32(_config["Email:Port"]);

    /// <summary>
    /// UseSsl
    /// </summary>
    public static bool UseSsl => Convert.ToBoolean(_config["Email:UseSsl"]);

    /// <summary>
    /// From
    /// </summary>
    public static class From
    {
        /// <summary>
        /// Username
        /// </summary>
        public static string Username => _config["Email:From:Username"];

        /// <summary>
        /// Password
        /// </summary>
        public static string Password => _config["Email:From:Password"];

        /// <summary>
        /// Name
        /// </summary>
        public static string Name => _config["Email:From:Name"];

        /// <summary>
        /// Address
        /// </summary>
        public static string Address => _config["Email:From:Address"];
    }

    /// <summary>
    /// To
    /// </summary>
    public static IDictionary<string, string> To
    {
        get
        {
            var dic = new Dictionary<string, string>();

            var emails = _config.GetSection("Email:To");
            foreach (IConfigurationSection section in emails.GetChildren())
            {
                var name = section["Name"];
                var address = section["Address"];

                dic.Add(name, address);
            }
            return dic;
        }
    }
}

分別介紹下每項的含義:

  • Host:發送郵件服務器地址。
  • Port:服務器地址端口號。
  • UseSsl:是否使用SSL方式。
  • From:發件人的賬號密碼,名稱及郵箱地址,一般郵箱地址和賬號是相同的。
  • To:收件人郵箱列表,也包含名稱和郵箱地址。

收件人郵箱列表我將其讀取為IDictionary<string, string>了,key是名稱,value是郵箱地址。

接着在.ToolKits層添加一個EmailHelper.cs,收發郵件我選擇了MailKitMailKit兩個庫,沒有安裝的先安裝一下,Install-Package MailKitInstall-Package MimeKit

直接新建一個發送郵件的方法SendAsync(),按照要求將基本的配置信息填進去,然後直接調用即可。

//EmailHelper.cs
using MailKit.Net.Smtp;
using Meowv.Blog.Domain.Configurations;
using MimeKit;
using System.Linq;
using System.Threading.Tasks;

namespace Meowv.Blog.ToolKits.Helper
{
    public static class EmailHelper
    {
        /// <summary>
        /// 發送Email
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static async Task SendAsync(MimeMessage message)
        {
            if (!message.From.Any())
            {
                message.From.Add(new MailboxAddress(AppSettings.Email.From.Name, AppSettings.Email.From.Address));
            }
            if (!message.To.Any())
            {
                var address = AppSettings.Email.To.Select(x => new MailboxAddress(x.Key, x.Value));
                message.To.AddRange(address);
            }

            using var client = new SmtpClient
            {
                ServerCertificateValidationCallback = (s, c, h, e) => true
            };
            client.AuthenticationMechanisms.Remove("XOAUTH2");

            await client.ConnectAsync(AppSettings.Email.Host, AppSettings.Email.Port, AppSettings.Email.UseSsl);
            await client.AuthenticateAsync(AppSettings.Email.From.Username, AppSettings.Email.From.Password);
            await client.SendAsync(message);
            await client.DisconnectAsync(true);
        }
    }
}

SendAsync(...)接收一個參數MimeMessage對象,這樣就完成了一個通用的發郵件方法,接着我們去需要發郵件的地方構造MimeMessage,調用SendAsync()

//WallpaperJob.cs
...
    // 發送Email
    var message = new MimeMessage
    {
        Subject = "【定時任務】壁紙數據抓取任務推送",
        Body = new BodyBuilder
        {
            HtmlBody = $"本次抓取到{wallpapers.Count()}條數據,時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}"
        }.ToMessageBody()
    };
    await EmailHelper.SendAsync(message);
...
//HotNewsJob.cs
...
    // 發送Email
    var message = new MimeMessage
    {
        Subject = "【定時任務】每日熱點數據抓取任務推送",
        Body = new BodyBuilder
        {
            HtmlBody = $"本次抓取到{hotNews.Count()}條數據,時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}"
        }.ToMessageBody()
    };
    await EmailHelper.SendAsync(message);
...

分別在兩個爬蟲腳本中添加發送Email,MimeMessage中設置了郵件主題Subject,正文Body,最後調用await EmailHelper.SendAsync(message)執行發送郵件操作。

編譯運行執行兩個定時任務,看看能否收到郵件提醒。

成功了,郵箱收到了兩條提醒。

還有一種比較特殊的用法,也介紹一下,如果想要發送帶圖片的郵件怎麼操作呢?注意不是附件,是將圖片內嵌在郵箱中。

一般常規都是有郵件模板的,將圖片的具體地址插入到img標籤中,這就不說了,這裏選擇另外一種方式。以前面添加的PuppeteerTestJob為例,正好我們生成了一張圖片的。將這種圖片以郵件的形式發出去。

public class PuppeteerTestJob : IBackgroundJob
{
    public async Task ExecuteAsync()
    {
        var path = Path.Combine(Path.GetTempPath(), "meowv.png");
        
        ...
        
        await page.ScreenshotAsync(path, new ScreenshotOptions
        {
            FullPage = true,
            Type = ScreenshotType.Png
        });

        // 發送帶圖片的Email
        var builder = new BodyBuilder();

        var image = builder.LinkedResources.Add(path);
        image.ContentId = MimeUtils.GenerateMessageId();

        builder.HtmlBody = "當前時間:{0}.<img src=\"cid:{1}\"/>".FormatWith(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), image.ContentId);

        var message = new MimeMessage
        {
            Subject = "【定時任務】每日熱點數據抓取任務推送",
            Body = builder.ToMessageBody()
        };
        await EmailHelper.SendAsync(message);
    }
}

先確定我們生成圖片的路徑 path ,將圖片生成Message-Id,然後賦值給ContentId,給模板中<img src=\"cid:{1}\"/>圖片標籤cid賦上值在調用發送郵件方法即可。

成功收到郵件,搞定了,你學會了嗎?

開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial

基於 abp vNext 和 .NET Core 開發博客項目,截止到本篇所用到的基礎模塊算是寫完了,如果對您有些許幫助請多多分享,我的所有原創文章都首發於我發個人公眾號:阿星Plus 。

下面有二維碼可以直接掃一掃,如果你不想關注也沒有關係,博客園我也會同步過來的。

不管因為什麼,如果你在學習這個項目或者跟着我一起做這個項目,裏面肯定還是有瑕疵的,大家可以根據自己的需求自行修改。

接下來應該還會更新博客所用到的接口,這個純屬於CRUD,可以自己先行開發,我這邊目前也不知道以什麼樣的方式展現給大家是最好的選擇。

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

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

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

數據結構 9 基礎數據結構 二叉堆 了解二叉堆的元素插入、刪除、構建二叉堆的代碼方式_網頁設計公司

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

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

是否記得我們在之前的學習中有學習到二叉樹 忘記的小夥伴們請查看:完全二叉樹的定義。

https://blogs.chaobei.xyz/archives/shuju2

二叉堆

二叉堆其實就是一個完全二叉樹 一起複習一下吧:關於二叉樹和滿二叉樹以及完全二叉樹的基本概念。

二叉樹

  • 每個節點下掛元素不超過2
  • 並且元素都是按照一定規律排列的

二叉樹規律

按照前人的總結,我們可以得出以下結論。

  • 一個深度為K 的二叉樹,最多包含節點數 2的k次方-1
  • 二叉樹指定n 層級所包含的節點數為 2的n-1次方

滿二叉樹

從字面意思我們可以理解到:這個二叉樹它是一種飽和的狀態,顧名思義稱作是滿二叉樹。

完全二叉樹

除去二叉樹的恭弘=叶 恭弘子節點,所有節點都包含有兩個節點,並且節點都是按照一定順序排列的,這樣的二叉樹被稱作是完全二叉樹

二叉堆類型

在上面我們已經提到過。二叉堆就是一種完全二叉樹、二叉樹的概念也已經了解到了。當然,現在應該分析二叉堆有有哪些性質

  • 最大堆
  • 最小堆

最大堆

最大堆的父節點元素的值都大於等於其兩個子元素的值

最小堆

反之,最小堆父節點元素的值,都小於等於其兩個子元素的值

二叉堆的堆頂部 則是這個堆序列最大或者最小的元素。

二叉堆的自我調整

二叉堆的自我調整,有以下幾種情況:

  • 新元素的插入
  • 元素的刪除
  • 構建二叉堆

我們以最上面的最小堆為例,講述如何將一個元素插入二叉堆、如何刪除一個元素、如何來構建一個二叉堆。

插入一個節點

按照上面最小堆的順序,我這裏再插入幾個其他元素方便觀察。假設這裏我插入一個元素1

元素1<元素6 進行上浮。子節點與父節點進行調換位置

元素1<元素3 進行上浮。子節點與父節點進行調換位置

元素1<元素2 進行上浮。到達堆頂部。

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

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

刪除一個元素

當前元素與子節點中最小元素進行比較、大於則交換位置下沉

假設我們刪除最頂層的元素1

二叉堆為了保證樹的結構、將二叉堆裏面尾部元素6填充到被刪除的位置。

當前元素6 與兩個子元素裏面最小元素 進行比較。大於則下沉

當前元素6 > 3 進行調換位置。元素6到達尾部。

規律:二叉堆的刪除元素和新增元素剛好是相反的

構建一個二叉堆

構建二叉堆、其實就是將一個原有的、無序的、完全二叉樹給他構建成有序的二叉堆。

假設我們來構建一個最小堆 我們這裏拿到一個無序的完全二叉樹如圖:

划重點:構建最小堆就是將非恭弘=叶 恭弘子節點進行下沉

1、操作元素5 元素5小於元素8 不進行移動

2、操作元素1 元素1小於元素5 不進行移動

3、操作元素7 省略步驟。最終結果如下:

4、操作元素3 省略步驟。最終結果如下:

至此,我們的無序完全二叉樹已經變成了一個有序的二叉最小堆

代碼實現

二叉堆雖然是一顆完全二叉樹,但是其存儲方式是順序存儲,使用的是數組、而不是鏈式指針。

我們可以發現如下規律:

  • 父元素左邊子元素位置 = 2*父元素下標 + 1
  • 父元素右邊子元素位置 = 2*父元素下標 + 2
public static void main(String[] args) {
        int[] array = {7, 1, 3, 5, 6, 4, 2, 8, 9};
        buildBinaryHeap(array);
        System.out.println(Arrays.toString(array));
    }

    public static void buildBinaryHeap(int[] array) {
        //除去恭弘=叶 恭弘子節點、將每個節點進行下沉操作
        for (int i = (array.length - 2) / 2; i >= 0; i--) {
            sinking(array, i);
        }
    }

    /**
     * 構建二叉堆、讓當前元素下沉
     *
     * @param array     被操作的數組
     * @param itemIndex 當前元素下標
     */
    public static void sinking(int[] array, int itemIndex) {
        //數組長度
        int length = array.length - 1;
        //父節點值
        int parent = array[itemIndex];

        //默認操作的是左孩子
        int childIndex = 2 * itemIndex + 1;

        while (childIndex < length) {

            //存在右邊子元素、並且右邊子元素值小於左邊
            if (childIndex + 1 < length && array[childIndex + 1] < array[childIndex]) {
                //切換到右邊元素
                childIndex++;
            }

            //小於等於則無需交換
            if (parent <= array[childIndex]) break;

            //無需交換、只需要將子元素移動到父元素位置即可
            array[itemIndex] = array[childIndex];
            itemIndex = childIndex;

            //改變左右子元素的下標
            childIndex = 2 * itemIndex + 1;
        }
        //最終將父元素移動到指定位置即可。
        array[itemIndex] = parent;
    }

代碼示例

https://gitee.com/mrc1999/Data-structure

小結

通過本節的學習,應該需要掌握二叉堆這個重要的數據結構、如何將一個完全二叉樹構建成一個二叉堆、並且二叉堆在插入元素、和刪除元素時候如何將原來的結構保持不變的。這該是我們學習的。
下一節將繼續學習二叉堆的堆排序、我們一起加油!

參考

https://mp.weixin.qq.com/s/cq2EhVtOTzTVpNpLDXfeJg

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

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

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

ASP.NET Core Blazor Webassembly 之 數據綁定_網頁設計公司

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

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

上一次我們學習了Blazor組件相關的知識(Asp.net Core Blazor Webassembly – 組件)。這次繼續學習Blazor的數據綁定相關的知識。當代前端框架都離不開數據綁定技術。數據綁定技術以數據為主導來驅動UI界面,用戶對數據的修改會實時提現在UI上,極大的提高了開發效率,讓開發者從繁瑣的dom操作中解脫出來。對於數據綁定.NET開發者並不會陌生,WPF里大量應用數據綁定技術,有過WPF開發經驗的同學其實很容易理解前端的數據綁定。總之數據綁定技術及其概念、思維極其重要。下面讓我們看看Blazor的數據綁定技術。

單向綁定

Blazor的數據綁定官方文檔是直接從雙向綁定開始的,但我覺得有必要說一下單向綁定。因為其他框架一般都會區分單向、雙向,比如vue的v-bind單向,v-model就是雙向。我們這裏分開講也有利於跟其他框架進行對比。下面我們實現一個計數器組件來演示下單向數據綁定。

使用@進行綁定

@page "/counter"

<p>Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

這個Counter組件默認的項目就自帶。跟我們使用服務端Razor一樣,使用@符號在需要替換值的地方插入對應的變量。這個值就會被渲染在相應的地方。當我們在前端修改變量的時候,對應的ui界面會同步進行修改。

使用@bind-{attribute}進行綁定

除了直接使用@進行綁定,我們還可以使用@bind-{attribute}來實現對html元素屬性的綁定,比如對style,class內容進行綁定。下面演示下對class進行綁定。我們把p元素的class綁定到“currentClass”字段。

@page "/counter"

<h1>Counter</h1>

<p @bind-class="currentClass" @bind-class:event="onchange">
    current count: @currentCount
</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private string currentClass = "text-danger";

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}

使用@bind-{attribute}進行綁定有個比較奇怪的問題,當你使用@bind-{attribute}進行綁定的時候必須同時指定@bind-{attribute}:event。@bind-{attribute}:event是用來指定雙向綁定的時候控件在發生某個事件的時候回寫值到綁定的字段上。可是p,div這種元素根本不可能會激發onchange,oninput這種事件,也不可能去修改綁定的字段的值,這個用法感覺有點多此一舉。
Blazor的單向數據綁定的用法跟ASP.NET Core MVC的Razor基本相似,不同點就是Blazor不需要Http回發到服務器就可以實時渲染新的界面出來。

雙向綁定

雙向綁定主要使用在一些輸入控件上,比如input,select等。當我們對這些控件上的值進行修改後會回寫綁定的字段。這種特性在表單場景中非常有用。我們定義一個用戶信息編輯的組件來演示下:

@page "/infoedit"

<p>
    userName: @userName
</p>
<p>
    sex: @sex
</p>
<p>
    userName: <input @bind="userName" />
</p>
<p>
    sex:
    <select @bind="sex">
        <option value="m">男</option>
        <option value="f">女</option>
    </select>
</p>

@code {
    private string userName="abc";
    private string sex="f";
}

當我們運行這個組件,在文本框進行修改后,鼠標點擊其他地方讓文本框失去焦點值就會回寫到綁定的字段上,上面的單向綁定信息會自動同步。但是如果你用過VUE或者Angularjs的雙向綁定就會覺得失去焦點再回寫字段數據太慢了,一點也不酷。要知道VUE的雙向綁定可是實時同步的,那麼Blazor如何做到在輸入的同時就更新值呢,答案是使用@bind:event來指定回寫的激發事件,我們改成“oninput”事件就可以實現:

<p>
    userName: <input @bind="userName" @bind:event="oninput"/>
</p>

雙向綁定的多種寫法

看到這裏也許你也明白了,@bind真正的本質是由對value的綁定和對某個事件的綁定協同完成的。這點跟VUE非常相似。@bind其實是@bind-value的縮寫,我們可以用@bind-value來實現雙向綁定:

<p>
    userName: <input @bind-value="userName" @bind-value:event="oninput"/>
</p>

以上寫法的效果跟@bind一模一樣。再進一步,@bind-value也只是對@的包裝,我們可以使用@來實現雙向綁定:

@page "/infoedit"

<p>
    userName: @userName
</p>
<p>
    sex: @sex
</p>
<p>
    userName: <input value="@userName" @oninput="oninput"/>
</p>
<p>
    sex:
    <select @bind="sex">
        <option value="m">男</option>
        <option value="f">女</option>
    </select>
</p>

@code {
    private string userName="abc";
    private string sex="f";

    private void oninput(ChangeEventArgs e)
    {
        userName = e.Value.ToString();
    }

}

以上代碼的效果跟@bind一模一樣。通過使用@對value直接進行綁定以及綁定一個oninput事件進行值的回寫,同樣實現了雙向綁定。

格式化時間字符串

使用@bind:format 可以對綁定時間類型字段的時候進行格式化:

出生日期:<input @bind="birthDay" @bind:format="yyyy-MM-dd" />

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

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

這個功能有點類似Angularjs的filter功能,但是目前只能對時間進行格式化,功能很弱。

父組件綁定數據到子組件

組件之間往往都是嵌套的,很多子組件都依賴父組件的數據來決定如何呈現,這種場景非常常見。我們還是繼續修改上面的編輯組件,用戶信息不在自己初始化,而是從父組件傳遞過來:
子組件:

====================child==================

<p>
    userName: <input @bind="UserInfo.UserName" />
</p>
<p>
    sex:
    <select @bind="UserInfo.Sex">
        <option value="m">男</option>
        <option value="f">女</option>
    </select>
</p>

<p>
    BrithDay:<input @bind="UserInfo.BrithDay" />
</p>
@code {

    [Parameter]
    public UserInfo UserInfo { get; set; }

    [Parameter]
    public EventCallback<UserInfo> UserInfoChanged { get; set; }
}

子組件定義一個UserInfo對象並且使用[Parameter]進行標記,同時如果父組件使用@bind-UserInfo來綁定的話,還必須實現一個UserInfoChanged事件。
父組件:

@page "/"
====================parent==================

<p>
    userName: @userInfo.UserName
</p>
<p>
    sex: @userInfo.Sex
</p>
<p>
    brithday: @userInfo.BrithDay
</p>


<InfoEdit @bind-UserInfo="userInfo"></InfoEdit>

@code {

    private UserInfo userInfo;

    protected override void OnInitialized()
    {
        userInfo = new UserInfo
        {
            UserName = "abc",
            Sex = "f",
            BrithDay = DateTime.Now
        };
        base.OnInitialized();
    }
}

父組件初始化一個UserInfo對象后通過@bind-UserInfo綁定給子組件。注意這裏我們修改子組件的值並不會同步給父組件,所以可以看到@bind-UserInfo的傳值還是單向的。

子組件傳值給父組件 ??

原來我以為父組件使用@bind-UserInfo並且子組件實現了對應的changed方法就可以實現子組件跟父組件的自動傳值,就跟input的雙向綁定一樣。但是不管我怎麼試都沒有卵用。如果只是單向的那為什麼要這麼大費周章?我直接使用屬性賦值不就可以了么?像下面這樣:

<InfoEdit UserInfo="userInfo" ></InfoEdit>

直接通過組件的屬性直接把父組件的數據傳遞到子組件,效果跟上面是一樣的,而且這樣子組件我還能少寫一個changed事件。我原本以為使用基本類型,比如string可以自動雙向綁定,然後並沒有什麼卵用。沒有辦法我繼續嘗試父組件監聽UserInfoChanged事件來接受子組件的數據,然後VS提示我同一個事件不能綁定兩次。

我已經無語了,難道要我再定義一個事件嗎?於是我放棄了@bind-來實現子組件給父組件傳值,我直接使用屬性賦值難道不比這個簡單嗎?
子組件修改數據的時候不斷對外拋事件:

====================child==================

<p>
    userName: <input @bind="UserInfo.UserName"  @oninput="InvokeChanged"/>
</p>

<p>
    sex:
    <select @bind="UserInfo.Sex">
        <option value="m">男</option>
        <option value="f">女</option>
    </select>
</p>

<p>
    BrithDay:<input @bind="UserInfo.BrithDay" />
</p>
@code {

    [Parameter]
    public UserInfo UserInfo { get; set; }

    [Parameter]
    public EventCallback<UserInfo> UserInfoChanged { get; set; }

    private void InvokeChanged()
    {
        UserInfoChanged.InvokeAsync(this.UserInfo);
        Console.WriteLine("InvokeChanged");
    }

}

父組件監聽事件后更新數據:

@page "/"
====================parent```==================

<p>
    userName: @userInfo.UserName
</p>
<p>
    sex: @userInfo.Sex
</p>
<p>
    brithday: @userInfo.BrithDay
</p>
<p>
    title: @title
</p>


<InfoEdit UserInfo="userInfo" UserInfoChanged="HandleUserInfoChanged"></InfoEdit>

@code {

    private UserInfo userInfo;

    private string title;

    protected override void OnInitialized()
    {
        userInfo = new UserInfo
        {
            UserName = "abc",
            Sex = "f",
            BrithDay = DateTime.Now
        };
        base.OnInitialized();
    }

    private void HandleUserInfoChanged(UserInfo info)
    {
        this.userInfo.UserName = info.UserName;

        Console.WriteLine("HandleUserInfoChanged");
    }


}


我原以為這樣就沒什麼問題了,可奇怪的是,父組件頁面重新渲染需要在子組件第二次修改數據后呈現且呈現的是前一次的。

到這裏我已經無語了,最後我只能在子組件直接添加一個按鈕,修改完後點擊保存來觸發InvokeChanged事件,這樣子是可以的:

====================child==================

<p>
    userName: <input @bind="UserInfo.UserName" />
</p>

<p>
    sex:
    <select @bind="UserInfo.Sex">
        <option value="m">男</option>
        <option value="f">女</option>
    </select>
</p>

<p>
    BrithDay:<input @bind="UserInfo.BrithDay" />
</p>

<button class="btn btn-danger" @onclick="InvokeChanged">保存</button>

@code {

    [Parameter]
    public UserInfo UserInfo { get; set; }

    [Parameter]
    public EventCallback<UserInfo> UserInfoChanged { get; set; }

    private void InvokeChanged()
    {
        UserInfoChanged.InvokeAsync(this.UserInfo);
        Console.WriteLine("InvokeChanged");
    }

}

到此數據綁定也演示完了,可是關於子組件往父組件傳值的事我實在沒像明白,難道是我哪裡錯了?

最後附上代碼:BlazorWasmDataBind

相關內容:
ASP.NET Core Blazor Webassembly 之 組件
ASP.NET Core Blazor 初探之 Blazor WebAssembly
ASP.NET Core Blazor 初探之 Blazor Server

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

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

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

這些狂拽酷炫吊炸天的自主SUV,讓合資SUV哭暈在廁所_網頁設計公司

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

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

38-15。98萬。對於無數的年輕人來說,沒有什麼能夠比低廉的價格來得更實在、吸引。7。38-15。98萬的售價意味着什麼。意味着你將能夠得到一個跟奧迪Q3完全一模一樣的外觀,在大學城把妹的時候,成功的幾率將會幾何級數地增長。

古語有雲:“走別人的路,讓別人無路可走。”這句話經常被我們引用在“一個絕世罕有的屌毛霸道且蠻不講理地侵佔別人的勞動成果,並且還自我得意洋洋“等情況上。不過讓人震驚的是,這句看似賤的毫無底線的話,竟然在我們高大上的汽車工業得到了充分的實踐。把這句話的效果發揮到淋漓精緻的,到底是哪家車企?各位吃瓜群眾趕緊來圍觀。

1雙環SRV

價格:9-12萬(停產)

真正的復刻,是不需要皮尺的,依靠的,僅僅是設計師的靈魂。雙環SRV就是基於這一哲學宗旨所誕生的偉大作品。之所以說它偉大,是因為在那個本田CRV風靡全國,動不動加價好多萬的年代(2004年左右),雙環汽車深知道普羅大眾錢包緊張的窘迫,頗為上進地不知道從哪裡搞來一輛本田CRV,照貓畫虎地造出了外形跟本田CRV一模一樣的雙環SRV。而這款車上市的時間,正正是東本本田國產CRV的那一年(2004年)。這樣的速度,起碼得堪稱是奇迹吧?

相對於本田CRV二十多萬的售價,雙環SRV的售價只需要9-12萬,這麼便宜的一輛城市SUV,瞬間就在全國各地炸開了鍋。不僅如此,雙環SRV還標誌了在當時看起來特牛逼的實木內飾、自動空調、真皮座椅等配置,哄得消費者不要不要的。據悉在很長的一段時間,雙環汽車有90%以上的銷量都是由雙環SRV所貢獻的。本田看不過眼了,開始了曠日持久的侵權狀告,但不曾讓人意料到的是,法院在2015年判決本田反賠償雙環汽車1600萬。

2眾泰SR7

價格: 7.38-15.98萬

相比起雙環SRV這種泰山級人物,眾泰SR7顯然就是一個不折不扣的的小學雞。不過兩者名字上的不謀而合,

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

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

似乎也已經昭示了眾泰SR7的非凡實力。當奧迪絞盡腦汁在思考如何慫恿更多的年輕人去購買旗下的緊湊型SUV—Q3的時候,拿着皮尺的眾泰設計師們便已經提前幫奧迪解決了這一個煩惱。為什麼?因為眾泰SR7的售價僅需要7.38-15.98萬。對於無數的年輕人來說,沒有什麼能夠比低廉的價格來得更實在、吸引。

7.38-15.98萬的售價意味着什麼?意味着你將能夠得到一個跟奧迪Q3完全一模一樣的外觀,在大學城把妹的時候,成功的幾率將會幾何級數地增長。其次,你能夠擁有一塊媲美特斯拉的12寸超大中控屏,你與那些開着特斯拉的人一樣,都是科技生活最忠實的擁躉。再次之,你能夠得到上坡輔助、自動駐車、全景天窗、全景攝像頭、定速巡航、電動座椅等一系列在這個級別車型上屬於無法想象的酷炫屌配置。這樣一輛的車,能夠體現出你非凡的豪華品位,能夠滿足你對前沿科技的渴望,能夠讓你毫無負擔地踏入一個更高層次的用車體驗。

3眾泰SR9

價格:未知

眾泰是中國近代汽車工業史上,最具有典型意義的汽車品牌。因為它不僅能抄、會抄,更重要的是,在他眼中,模仿是不應該有條條框框的,模仿是一項藝術。如果說眾泰SR7的推出,讓中國的年輕人提前50年踏入了豪門。那眾泰SR9的推出,無疑是讓中國的年輕人提前100年踏入了豪門。你是否擁有一個可望不可即的保時捷夢?如今眾泰的“保時捷”來了。

根據最新的消息,外形已經最終確定的眾泰SR9與保時捷的高性能SUV—Macan高度一致,各位悶騷的少年只需要後期到汽配城自行更換車標,即可升級為保時捷Macan。動力方面配備了2.0T的發動機,變速箱有5MT以及6DCT可選,要跑贏宏光S相信不是一件難事。至於在配置上,眾泰SR9再度實現了高度的突破,分別搭載了自動大燈、19寸鋁合金輪轂、全景天窗、車道偏離、盲點監測、電動尾門,做到了完全對標保時捷Macan。在大家關心的價格上,眾泰官方還沒有透露,不過根據以往的定價猜測,起售價應該會在11萬的範圍。不過我還是有一點建議,如果眾泰是不是應該把保時捷的車標作為後期選裝件?

本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

中央宣講團在各地宣講黨的十九屆五中全會精神_網頁設計公司

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

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

2020-11-20 來源:央視《新聞聯播》

2020-11-20
來源:央視《新聞聯播》 分享到:
[打印]
字號:[大] [中] [小]
  連日來,中央宣講團成員走進湖南、山東、廣西等地,對黨的十九屆五中全會精神進行闡釋宣講,並深入基層與幹部群眾交流互動。   中央宣講團成員、財政部部長劉昆近日在湖南長沙做宣講報告,他從深刻認識我國進入新發展階段的重大意義、有利條件和重要特徵等四個方面對全會精神進行講解,

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

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

並來到高校和文創產業園與幹部群眾座談。   在山東濟南,中央宣講團成員、自然資源部部長陸昊圍繞深刻認識全會的意義、2035年遠景目標和“十四五”時期主要目標任務等內容對全會精神進行闡釋。山東各地3萬多人在主會場和各分會場聽取了宣講報告。   宣講期間,陸昊還來到德州市的鄉村、社區,就耕地保護、村莊規劃、農村建設用地等問題與基層幹部群眾互動交流。   中央宣講團成員、生態環境部黨組書記孫金龍近日在廣西南寧做宣講報告。會後,他還深入廣西北部灣國際港務集團,就學習貫徹全會精神和大家交流。   來源:央視《新聞聯播》

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

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

一頁式詐騙網站系列:只要1600元的迷你壹號本是真的嗎?_網頁設計公司

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

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

大家都知道臉書對各種詐騙一頁式網站根本沒在管的,所以各種奇怪的山寨或假品橫行,這次挑戰的是一頁式網站販售的「壹號本」迷你筆電,這個品牌在中國也不便宜,一般要價三萬台幣左右,這次在臉書廣告上看到竟然只要1600元?!用腳掌想也知道有問題,所以阿達買回來挑戰啦!結果裡面給的東西是…. 有什麼有趣的怪東西歡迎投稿告知,我買來開箱看看XDD

一頁式詐騙網站系列:只要1600元的迷你壹號本是真的嗎?

最近在臉書上又看到一個一頁式網站廣告,內容就是對岸的「壹號本」筆電,但點進去果然有問題(請大家不要也跟著買嘿,除非你也想試試XD):

 

裡面寫一台原價18999,特價只要1699,用膝蓋想也知道有問題,不過因為同溫層裡面聽說有幾個有故意定來看看,所以讓我也很好奇,本來以為可能是英漢翻譯機或是庫存的爛小筆電之類的,想說拍片沒梗試試:

而這次被冒名的苦主壹號本在中國其實還蠻有名的,阿輝也開箱過,一般價位在2~3萬台幣左右:

 

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

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

至於阿達花1699買到的「壹號本」裡面到底是什麼呢?大家自己看影片吧,記得訂閱並開啟小鈴鐺,也歡迎在影片底下留言推薦瞎品:

 

不過最後還是要唸一下,臉書TMD真的都不管這些詐騙購物網站的,就算檢舉也屹立不搖,他們還會開一堆不同頁面與粉絲頁繼續搞…(更多踩雷開箱請點我)

必看!如何 預防臉書詐騙 及被詐騙後的處理方式

您也許會喜歡:

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

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

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

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

Jpa使用詳解_網頁設計公司

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

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

目錄

  • ORM思想
    • 1.ORM概述
    • 2.為什麼要使用ORM
    • 3.常見的ORM框架
  • JPA簡介
    • 1.JPA概述
    • 2.JPA的優勢
    • 3.JPA與hibernate的關係
  • JPA入門案例
    • 1.搭建開發環境
      • 常用註解說明
  • JPA主鍵生成策略
  • JPA的API介紹
    • 1.Persistence對象
    • 2.EntityManagerFactory
    • 3.EntityManager
    • 4.EntityTransaction

ORM思想

1.ORM概述

ORM(Object-Relational Mapping) 表示對象關係映射。在面向對象的軟件開發中,通過ORM,就可以把對象映射到關係型數據庫中。只要有一套程序能夠做到建立對象與數據庫的關聯,操作對象就可以直接操作數據庫數據,就可以說這套程序實現了ORM對象關係映射

簡單的說:ORM就是建立實體類和數據庫表之間的關係,從而達到操作實體類就相當於操作數據庫表的目的。

2.為什麼要使用ORM

當實現一個應用程序時(不使用O/R Mapping),我們可能會寫特別多數據訪問層的代碼,從數據庫保存數據、修改數據、刪除數據,而這些代碼都是重複的。而使用ORM則會大大減少重複性代碼。對象關係映射(Object Relational Mapping,簡稱ORM),主要實現程序對象到關係數據庫數據的映射。

3.常見的ORM框架

當實現一個應用程序時(不使用O/R Mapping),我們可能會寫特別多數據訪問層的代碼,從數據庫保存數據、修改數據、刪除數據,而這些代碼都是重複的。而使用ORM則會大大減少重複性代碼。對象關係映射(Object Relational Mapping,簡稱ORM),主要實現程序對象到關係數據庫數據的映射。

JPA簡介

1.JPA概述

JPA的全稱是Java Persistence API, 即Java 持久化API,是SUN公司推出的一套基於ORM的規範,內部是由一系列的接口和抽象類構成。JPA通過JDK 5.0註解描述對象-關係表的映射關係,並將運行期的實體對象持久化到數據庫中。

2.JPA的優勢

1. 標準化

JPA 是 JCP 組織發布的 Java EE 標準之一,因此任何聲稱符合 JPA 標準的框架都遵循同樣的架構,提供相同的訪問API,這保證了基於JPA開發的企業應用能夠經過少量的修改就能夠在不同的JPA框架下運行。

2. 容器級特性的支持

JPA框架中支持大數據集、事務、併發等容器級事務,這使得 JPA 超越了簡單持久化框架的局限,在企業應用發揮更大的作用。

3. 簡單方便

JPA的主要目標之一就是提供更加簡單的編程模型:在JPA框架下創建實體和創建Java 類一樣簡單,沒有任何的約束和限制,只需要使用 javax.persistence.Entity進行註釋,JPA的框架和接口也都非常簡單,沒有太多特別的規則和設計模式的要求,開發者可以很容易的掌握。JPA基於非侵入式原則設計,因此可以很容易的和其它框架或者容器集成

4. 查詢能力

JPA的查詢語言是面向對象而非面向數據庫的,它以面向對象的自然語法構造查詢語句,可以看成是Hibernate HQL的等價物。JPA定義了獨特的JPQL(Java Persistence Query Language),JPQL是EJB QL的一種擴展,它是針對實體的一種查詢語言,操作對象是實體,而不是關係數據庫的表,而且能夠支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL 才能夠提供的高級查詢特性,甚至還能夠支持子查詢。

5. 高級特性

JPA 中能夠支持面向對象的高級特性,如類之間的繼承、多態和類之間的複雜關係,這樣的支持能夠讓開發者最大限度的使用面向對象的模型設計企業應用,而不需要自行處理這些特性在關係數據庫的持久化。

3.JPA與hibernate的關係

JPA規範本質上就是一種ORM規範,注意不是ORM框架——因為JPA並未提供ORM實現,它只是制訂了一些規範,提供了一些編程的API接口,但具體實現則由服務廠商來提供實現。

JPA和Hibernate的關係就像JDBC和JDBC驅動的關係,JPA是規範,Hibernate除了作為ORM框架之外,它也是一種JPA實現。JPA怎麼取代Hibernate呢?JDBC規範可以驅動底層數據庫嗎?答案是否定的,也就是說,如果使用JPA規範進行數據庫操作,底層需要hibernate作為其實現類完成數據持久化工作。

JPA入門案例

1.搭建開發環境

第一步:創建一個maven工程

第二步:引入jar包

<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.hibernate.version>5.0.7.Final</project.hibernate.version>
    </properties>

<dependencies>
    <!-- junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>

    <!-- hibernate對jpa的支持包 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${project.hibernate.version}</version>
    </dependency>

    <!-- c3p0 -->
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-c3p0</artifactId>
        <version>${project.hibernate.version}</version>
    </dependency>

    <!-- log日誌 -->
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <!-- Mysql and MariaDB -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.6</version>
    </dependency>
</dependencies>

第三步:創建數據庫表

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

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

 /*創建客戶表*/
    CREATE TABLE cst_customer (
      cust_id bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客戶編號(主鍵)',
      cust_name varchar(32) NOT NULL COMMENT '客戶名稱(公司名稱)',
      cust_source varchar(32) DEFAULT NULL COMMENT '客戶信息來源',
      cust_industry varchar(32) DEFAULT NULL COMMENT '客戶所屬行業',
      cust_level varchar(32) DEFAULT NULL COMMENT '客戶級別',
      cust_address varchar(128) DEFAULT NULL COMMENT '客戶聯繫地址',
      cust_phone varchar(64) DEFAULT NULL COMMENT '客戶聯繫電話',
      PRIMARY KEY (`cust_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

第四步:創建客戶實體類

public class Customer {

    private Long custId;
    private String custName;
    private String custSource;
    private String custIndustry;
    private String custLevel;
    private String custAddress;
    private String custPhone;

    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", custPhone='" + custPhone + '\'' +
                '}';
    }
}

第五步:編寫實體類和數據庫表的映射配置[重點]

import javax.persistence.*;

@Entity //聲明實體類
@Table(name="cst_customer") //建立實體類和表的映射關係
public class Customer {

    @Id//聲明當前私有屬性為主鍵
    @GeneratedValue(strategy= GenerationType.IDENTITY) //配置主鍵的生成策略
    @Column(name="cust_id") //指定和表中cust_id字段的映射關係
    private Long custId;

    @Column(name="cust_name") //指定和表中cust_name字段的映射關係
    private String custName;

    @Column(name="cust_source")//指定和表中cust_source字段的映射關係
    private String custSource;

    @Column(name="cust_industry")//指定和表中cust_industry字段的映射關係
    private String custIndustry;

    @Column(name="cust_level")//指定和表中cust_level字段的映射關係
    private String custLevel;

    @Column(name="cust_address")//指定和表中cust_address字段的映射關係
    private String custAddress;

    @Column(name="cust_phone")//指定和表中cust_phone字段的映射關係
    private String custPhone;

    public Long getCustId() {
        return custId;
    }
    public void setCustId(Long custId) {
        this.custId = custId;
    }
    public String getCustName() {
        return custName;
    }
    public void setCustName(String custName) {
        this.custName = custName;
    }
    public String getCustSource() {
        return custSource;
    }
    public void setCustSource(String custSource) {
        this.custSource = custSource;
    }
    public String getCustIndustry() {
        return custIndustry;
    }
    public void setCustIndustry(String custIndustry) {
        this.custIndustry = custIndustry;
    }
    public String getCustLevel() {
        return custLevel;
    }
    public void setCustLevel(String custLevel) {
        this.custLevel = custLevel;
    }
    public String getCustAddress() {
        return custAddress;
    }
    public void setCustAddress(String custAddress) {
        this.custAddress = custAddress;
    }
    public String getCustPhone() {
        return custPhone;
    }
    public void setCustPhone(String custPhone) {
        this.custPhone = custPhone;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "custId=" + custId +
                ", custName='" + custName + '\'' +
                ", custSource='" + custSource + '\'' +
                ", custIndustry='" + custIndustry + '\'' +
                ", custLevel='" + custLevel + '\'' +
                ", custAddress='" + custAddress + '\'' +
                ", custPhone='" + custPhone + '\'' +
                '}';
    }
}

常用註解說明

       @Entity
        	作用:指定當前類是實體類。
        @Table
        	作用:指定實體類和表之間的對應關係。
        	屬性:
        		name:指定數據庫表的名稱
        @Id
        	作用:指定當前字段是主鍵。
        @GeneratedValue
        	作用:指定主鍵的生成方式。。
        	屬性:
        		strategy :指定主鍵生成策略。
        @Column
        	作用:指定實體類屬性和數據庫表之間的對應關係
        	屬性:
        		name:指定數據庫表的列名稱。
        		unique:是否唯一  
        		nullable:是否可以為空  
        		inserttable:是否可以插入  
        		updateable:是否可以更新  
        		columnDefinition: 定義建表時創建此列的DDL  
        		secondaryTable: 從表名。如果此列不建在主表上(默認建在主表),該屬性定義該列所在從表的名字搭建開發環境[重點]

第六步:配置JPA的核心配置文件

在java工程的resources路徑下創建一個名為META-INF的文件夾,在此文件夾下創建一個名為persistence.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

    <!--配置持久化單元
		name:持久化單元名稱
		transaction-type:事務類型
		 	RESOURCE_LOCAL:本地事務管理
		 	JTA:分佈式事務管理 -->
    <persistence-unit name="myJpa" transaction-type="RESOURCE_LOCAL">

        <!--配置JPA規範的服務提供商 也就是JPA的具體實現 -->
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <properties>
            <!-- 數據庫驅動 -->
            <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
            <!-- 數據庫地址 -->
            <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa" />
            <!-- 數據庫用戶名 使用你自己的用戶名 -->
            <property name="javax.persistence.jdbc.user" value="root" />
            <!-- 數據庫密碼 用你自己的密碼 -->
            <property name="javax.persistence.jdbc.password" value="123456" />

            <!--jpa提供者的可選配置:我們的JPA規範的提供者為hibernate,所以jpa的核心配置中兼容hibernate的配 -->
            <property name="hibernate.show_sql" value="true" />
            <property name="hibernate.format_sql" value="true" />
            <property name="hibernate.hbm2ddl.auto" value="create" />

        </properties>

    </persistence-unit>

</persistence>

第七步:編寫單元測試

在test目錄下面創建JpaTest測試類

import cn.wgzblog.entity.Customer;
import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;

public class JpaTest {

    @Test
    public void test() {
        /**
         * 創建實體管理類工廠,藉助Persistence的靜態方法獲取
         * 		其中傳遞的參數為持久化單元名稱,需要jpa配置文件中指定
         */
        EntityManagerFactory factory = Persistence.createEntityManagerFactory("myJpa");
        //創建實體管理類
        EntityManager entityManager = factory.createEntityManager();
        //獲取事務對象
        EntityTransaction transaction = entityManager.getTransaction();
        //開啟事務
        transaction.begin();
        //設置實體類
        Customer customer=new Customer();
        customer.setCustAddress("上海陸家嘴");
        customer.setCustName("五公子");
        customer.setCustPhone("18898886666");
        //保存操作
        entityManager.persist(customer);
        //提交事務
        transaction.commit();
        // 釋放資源
        entityManager.close();
        factory.close();
    }
}

輸出結果:

Hibernate: 
    drop table if exists cst_customer
Hibernate: 
    create table cst_customer (
        cust_id bigint not null auto_increment,
        cust_address varchar(255),
        cust_industry varchar(255),
        cust_level varchar(255),
        cust_name varchar(255),
        cust_phone varchar(255),
        cust_source varchar(255),
        primary key (cust_id)
    )
Hibernate: 
    insert 
    into
        cst_customer
        (cust_address, cust_industry, cust_level, cust_name, cust_phone, cust_source) 
    values
        (?, ?, ?, ?, ?, ?)

JPA主鍵生成策略

通過annotation(註解)來映射hibernate實體的,基於annotation的hibernate主鍵標識為@Id, 其生成規則由@GeneratedValue設定的.這裏的@id和@GeneratedValue都是JPA的標準用法。

JPA提供的四種標準用法為TABLE,SEQUENCE,IDENTITY,AUTO。

具體說明如下:

IDENTITY:主鍵由數據庫自動生成(主要是自動增長型)

用法:

@Id  
@GeneratedValue(strategy = GenerationType.IDENTITY) 
private Long custId;

SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列。

用法:

@Id  
@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="payablemoney_seq")  
@SequenceGenerator(name="payablemoney_seq", sequenceName="seq_payment")  
private Long custId;


//@SequenceGenerator源碼中的定義
@Target({TYPE, METHOD, FIELD})   
@Retention(RUNTIME)  
public @interface SequenceGenerator {  
    //表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的“generator”值中
    String name();  
    //屬性表示生成策略用到的數據庫序列名稱。
    String sequenceName() default "";  
    //表示主鍵初識值,默認為0
    int initialValue() default 0;  
    //表示每次主鍵值增加的大小,例如設置1,則表示每次插入新記錄后自動加1,默認為50
    int allocationSize() default 50;  
}

AUTO*:主鍵由程序控制

用法:

@Id  
@GeneratedValue(strategy = GenerationType.AUTO)  
private Long custId;

TABLE:使用一個特定的數據庫表格來保存主鍵

@Id  
@GeneratedValue(strategy = GenerationType.TABLE, generator="payablemoney_gen")  
@TableGenerator(name = "pk_gen",  
                table="tb_generator",  
                pkColumnName="gen_name",  
                valueColumnName="gen_value",  
                pkColumnValue="PAYABLEMOENY_PK",  
                allocationSize=1  
               ) 
private Long custId;


//@TableGenerator的定義:
@Target({TYPE, METHOD, FIELD})   
@Retention(RUNTIME)  
public @interface TableGenerator {  
    //表示該表主鍵生成策略的名稱,它被引用在@GeneratedValue中設置的“generator”值中
    String name();  
    //表示表生成策略所持久化的表名,例如,這裏表使用的是數據庫中的“tb_generator”。
    String table() default "";  
    //catalog和schema具體指定表所在的目錄名或是數據庫名
    String catalog() default "";  
    String schema() default "";  
    //屬性的值表示在持久化表中,該主鍵生成策略所對應鍵值的名稱。例如在“tb_generator”中將“gen_name”作為主鍵的鍵值
    String pkColumnName() default "";  
    //屬性的值表示在持久化表中,該主鍵當前所生成的值,它的值將會隨着每次創建累加。例如,在“tb_generator”中將“gen_value”作為主鍵的值 
    String valueColumnName() default "";  
    //屬性的值表示在持久化表中,該生成策略所對應的主鍵。例如在“tb_generator”表中,將“gen_name”的值為“CUSTOMER_PK”。 
    String pkColumnValue() default "";  
    //表示主鍵初識值,默認為0。 
    int initialValue() default 0;  
    //表示每次主鍵值增加的大小,例如設置成1,則表示每次創建新記錄后自動加1,默認為50。
    int allocationSize() default 50;  
    UniqueConstraint[] uniqueConstraints() default {};  
} 

//這裏應用表tb_generator,定義為 :
CREATE TABLE  tb_generator (  
    id NUMBER NOT NULL,  
    gen_name VARCHAR2(255) NOT NULL,  
    gen_value NUMBER NOT NULL,  
    PRIMARY KEY(id)  
)

JPA的API介紹

1.Persistence對象

Persistence對象主要作用是用於獲取EntityManagerFactory對象的 。通過調用該類的createEntityManagerFactory靜態方法,根據配置文件中持久化單元名稱創建EntityManagerFactory。

//1. 創建 EntitymanagerFactory
String unitName = "myJpa";
EntityManagerFactory factory= Persistence.createEntityManagerFactory(unitName);

2.EntityManagerFactory

EntityManagerFactory 接口主要用來創建 EntityManager 實例

//創建實體管理類
EntityManager em = factory.createEntityManager();

由於EntityManagerFactory 是一個線程安全的對象(即多個線程訪問同一個EntityManagerFactory 對象不會有線程安全問題),並且EntityManagerFactory 的創建極其浪費資源,所以在使用JPA編程時,我們可以對EntityManagerFactory 的創建進行優化,只需要做到一個工程只存在一個EntityManagerFactory 即可

3.EntityManager

在 JPA 規範中, EntityManager是完成持久化操作的核心對象。實體類作為普通 java對象,只有在調用 EntityManager將其持久化后才會變成持久化對象。EntityManager對象在一組實體類與底層數據源之間進行 O/R 映射的管理。它可以用來管理和更新 Entity Bean, 根椐主鍵查找 Entity Bean, 還可以通過JPQL語句查詢實體。

我們可以通過調用EntityManager的方法完成獲取事務,以及持久化數據庫的操作

方法說明:

getTransaction : 獲取事務對象
persist : 保存操作
merge : 更新操作
remove : 刪除操作
find/getReference : 根據id查詢

4.EntityTransaction

在 JPA 規範中, EntityTransaction是完成事務操作的核心對象,對於EntityTransaction在我們的java代碼中承接的功能比較簡單

begin:開啟事務
commit:提交事務
rollback:回滾事務

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

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

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

小伙竟然每晚偷車只為約妹子…老婆在身邊千萬別手賤點開_網頁設計公司

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

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

保時捷-Macan新車指導價:58。80-112。41萬最強動力:3。6升 雙渦輪增壓 400馬力點評:眾泰的SR9令了保時捷Macan火了又火,無論是外觀還是內飾,都被抄得完無體膚。要說保時捷Macan能把妹,更多的是保時捷這個豪車品牌,老實說,有那個錢不會買保時捷,性價比真的不高,更多的是品牌效應,不過貌似這樣就足以了。

前幾天有一則新聞的標題是這樣的,

絕對會令你哭笑不得。

“男子每晚偷豪車把妹 清晨又加滿油停回原位”

杭州一小伙子稱在外撿到一把鑰匙,“恰好”遇上在地下停車庫的正主(路虎攬勝),便打算每晚開路虎裝富二代出去“把妹”,次日凌晨五六點將路虎加滿油擦乾淨停回原位。

當然,最後的結果就是被土豪車主(家裡5輛私家車,路虎不常開)發現,報警之後不久就捉到了嫌疑人,然而嫌疑人已經快活了幾個晚上,可憐那些上當的姑娘了…

不得不說這是一個機智的小伙子,開句玩笑說的就是小伙子並沒有偷車,而是“借車”,借車不忘加滿油同時還擦乾淨,這才是平時借車的人應該學習的嘛!

年輕人嘛,買車當然得看外觀,那麼哪些車型你覺得最具把妹潛質的呢?認為下面幾款車型,把妹杠杠的!妹子看到都想上車!

路虎(進口)-攬勝運動版

新車指導價:92.80-229.80萬

最強動力:5.0升 机械增壓 551馬力

點評:記得接觸路虎攬勝是在上一年底,試駕車是5.0T V8 SVR版本(兩百多萬的裸車…),印象最深的就是攬勝的外觀霸氣,車子是真的大,在主駕駛位坐着看路上的普通SUV,就像轎車一樣,坐姿特別高。另外最令人深刻的是,V8發動機的排氣聲確實響亮,記得那時在地下停車場啟動車輛,轟炸了全場,妹子都受到驚嚇撲到身上了。

捷豹-捷豹F-TYpE

新車指導價:79.80-198.80萬

最強動力:5.0升 机械增壓 575馬力

點評:要說帶妹,

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

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

肯定少不了敞篷車。敞篷車最愛的就是捷豹F-TYpE,令最着迷的是F-TYpE的車尾跟排氣聲,特別迷人。捷豹F-TYpE SVR版本的官方0-100km/h加速(s)為3.7秒,簡直要上天了。據海外媒體報道,捷豹F-TYpE的改款車型將增加一款全新入門版本,新車搭載2.0L渦輪增壓發動機,價格大概六十萬左右,離帶妹的距離還有五十九萬的差距…

保時捷-Macan

新車指導價:58.80-112.41萬

最強動力:3.6升 雙渦輪增壓 400馬力

點評:眾泰的SR9令了保時捷Macan火了又火,無論是外觀還是內飾,都被抄得完無體膚。要說保時捷Macan能把妹,更多的是保時捷這個豪車品牌,老實說,有那個錢不會買保時捷,性價比真的不高,更多的是品牌效應,不過貌似這樣就足以了…妹子看着保時捷標都把持不住了。

雪佛蘭(進口)-科邁羅

新車指導價:45.58-49.98萬

最強動力:3.6升 328馬力

點評:大部分人是從電影《變形金剛》系列認識到大黃蜂科邁羅,一個正派的主角。科邁羅是美式典型的肌肉車,一看就是一個“壯漢”,特別適合開去健身房把妹,當然也少不了自己擁有八塊腹肌(已經純火爐青九九歸一了)。現款的科邁羅動力方面相對弱一點,不過有關消息得知,海外曝光了全新科邁羅ZL1,新車搭載6.2L V8机械增壓發動機,擁有660馬力的強悍數據,簡直上天了有木有!

福特(進口)-Mustang

新車指導價:39.98-76.40萬

最強動力:5.0升 422馬力

點評:福特野馬也是美式肌肉車的代表車型,歷史源遠流長。同樣,很多人對它的認識是從電影《速度與激情》系列開始的,正派主角的御用車輛,在電影中的上鏡率非常高,通常都以改裝車的身份出現,所以證明野馬也是極具改裝潛質。福特野馬最好的購買渠道還是平行進口車,最低配才不過三十萬出頭,也算是物美價廉了。

各類超跑就不提了,

那根本不需要去主動撩妹,

這都是被妹撩了好不好!

不說了,

先買個超跑模型回家,

放在車內看看有沒有妹子撩好了…本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

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

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

全球調查報告 500多座開發中水壩位保護區內 恐失生態系保護力_網頁設計公司

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

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

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

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

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