基於 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 開發博客項目 – 博客接口實戰篇(一)

上篇文章完成了兩個接口:文章列表頁、文章詳情頁,本篇繼續。

分類列表

分析:這裏多了一個統計文章數量的字段,可以直接新建一個模型QueryCategoryDto.cs繼承CategoryDto

//QueryCategoryDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class QueryCategoryDto : CategoryDto
    {
        /// <summary>
        /// 總數
        /// </summary>
        public int Count { get; set; }
    }
}

添加查詢分類列表接口和緩存接口。

//IBlogService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Blog
{
    public partial interface IBlogService
    {
        /// <summary>
        /// 查詢分類列表
        /// </summary>
        /// <returns></returns>
        Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync();
    }
}
//IBlogCacheService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Caching.Blog
{
    public partial interface IBlogCacheService
    {
        /// <summary>
        /// 查詢分類列表
        /// </summary>
        /// <param name="factory"></param>
        /// <returns></returns>
        Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync(Func<Task<ServiceResult<IEnumerable<QueryCategoryDto>>>> factory);
    }
}

分別實現這兩個接口。

//BlogCacheService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static Meowv.Blog.Domain.Shared.MeowvBlogConsts;

namespace Meowv.Blog.Application.Caching.Blog.Impl
{
    public partial class BlogCacheService
    {
        private const string KEY_QueryCategories = "Blog:Category:QueryCategories";

        /// <summary>
        /// 查詢分類列表
        /// </summary>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync(Func<Task<ServiceResult<IEnumerable<QueryCategoryDto>>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_QueryCategories, factory, CacheStrategy.ONE_DAY);
        }
    }
}
//BlogService.Category.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Blog.Impl
{
    public partial class BlogService
    {
        /// <summary>
        /// 查詢分類列表
        /// </summary>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync()
        {
            return await _blogCacheService.QueryCategoriesAsync(async () =>
            {
                var result = new ServiceResult<IEnumerable<QueryCategoryDto>>();

                var list = from category in await _categoryRepository.GetListAsync()
                           join posts in await _postRepository.GetListAsync()
                           on category.Id equals posts.CategoryId
                           group category by new
                           {
                               category.CategoryName,
                               category.DisplayName
                           } into g
                           select new QueryCategoryDto
                           {
                               CategoryName = g.Key.CategoryName,
                               DisplayName = g.Key.DisplayName,
                               Count = g.Count()
                           };

                result.IsSuccess(list);
                return result;
            });
        }
    }
}

緩存就不說了,查詢分類列表,聯合查詢文章和分類兩張表,關聯字段為CategoryId,然後分組,計算出對應的數量,在BlogController中添加API。

/// <summary>
/// 查詢分類列表
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("categories")]
public async Task<ServiceResult<IEnumerable<QueryCategoryDto>>> QueryCategoriesAsync()
{
    return await _blogService.QueryCategoriesAsync();
}

標籤列表

分析:和分類列表差不多,新建模型QueryTagDto.cs繼承TagDto

//QueryTagDto.cs
namespace Meowv.Blog.Application.Contracts.Blog
{
    public class QueryTagDto : TagDto
    {
        /// <summary>
        /// 總數
        /// </summary>
        public int Count { get; set; }
    }
}

添加查詢標籤列表接口和緩存接口。

//IBlogCacheService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Caching.Blog
{
    public partial interface IBlogCacheService
    {
        /// <summary>
        /// 查詢標籤列表
        /// </summary>
        /// <param name="factory"></param>
        /// <returns></returns>
        Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync(Func<Task<ServiceResult<IEnumerable<QueryTagDto>>>> factory);
    }
}
//IBlogService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Blog
{
    public partial interface IBlogService
    {
        /// <summary>
        /// 查詢標籤列表
        /// </summary>
        /// <returns></returns>
        Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync();
    }
}

分別實現這兩個接口。

//BlogCacheService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using static Meowv.Blog.Domain.Shared.MeowvBlogConsts;

namespace Meowv.Blog.Application.Caching.Blog.Impl
{
    public partial class BlogCacheService
    {
        private const string KEY_QueryTags = "Blog:Tag:QueryTags";

        /// <summary>
        /// 查詢標籤列表
        /// </summary>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync(Func<Task<ServiceResult<IEnumerable<QueryTagDto>>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_QueryTags, factory, CacheStrategy.ONE_DAY);
        }
    }
}
//BlogService.Tag.cs
using Meowv.Blog.Application.Contracts.Blog;
using Meowv.Blog.ToolKits.Base;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Meowv.Blog.Application.Blog.Impl
{
    public partial class BlogService
    {
        /// <summary>
        /// 查詢標籤列表
        /// </summary>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync()
        {
            return await _blogCacheService.QueryTagsAsync(async () =>
            {
                var result = new ServiceResult<IEnumerable<QueryTagDto>>();

                var list = from tags in await _tagRepository.GetListAsync()
                           join post_tags in await _postTagRepository.GetListAsync()
                           on tags.Id equals post_tags.TagId
                           group tags by new
                           {
                               tags.TagName,
                               tags.DisplayName
                           } into g
                           select new QueryTagDto
                           {
                               TagName = g.Key.TagName,
                               DisplayName = g.Key.DisplayName,
                               Count = g.Count()
                           };

                result.IsSuccess(list);
                return result;
            });
        }
    }
}

查詢標籤列表需要聯合查詢tags和post_tags,根據TagId進行關聯,然後分組從而獲取標籤下文章的總數,在BlogController中添加API。

/// <summary>
/// 查詢標籤列表
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("tags")]
public async Task<ServiceResult<IEnumerable<QueryTagDto>>> QueryTagsAsync()
{
    return await _blogService.QueryTagsAsync();
}

分類名稱&文章列表

分析:此頁面下包含兩個接口,查詢分類的名稱和當前分類下的文章列表,和文章列表不同的是,它不帶分頁。分類包含兩個字段,分類名稱和展示名稱,我們要把真正的名稱查詢出來展示在頁面上。

分類名稱

不需要給他添加返回模型,直接返回一個string類型即可,同時給一個查詢參數name,添加獲取分類名稱接口和緩存接口。

//IBlogService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetCategoryAsync(string name);
//IBlogCacheService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetCategoryAsync(string name, Func<Task<ServiceResult<string>>> factory);

實現這兩個接口。

//BlogCacheService.Category.cs
...
    public partial class BlogCacheService
    {
        private const string KEY_GetCategory = "Blog:Category:GetCategory-{0}";

        /// <summary>
        /// 獲取分類名稱
        /// </summary>
        /// <param name="name"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<string>> GetCategoryAsync(string name, Func<Task<ServiceResult<string>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_GetCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
        }
    }
...
//BlogService.Category.cs
/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetCategoryAsync(string name)
{
    return await _blogCacheService.GetCategoryAsync(name, async () =>
    {
        var result = new ServiceResult<string>();

        var category = await _categoryRepository.FindAsync(x => x.DisplayName.Equals(name));
        if (null == category)
        {
            result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("分類", name));
            return result;
        }

        result.IsSuccess(category.CategoryName);
        return result;
    });
}

FormatWith()是擴展方法,ResponseText.WHAT_NOT_EXIST是之前說過的常量,直接查詢是否存在當前name的分類,如果不存在給出錯誤提示,存在的話,則只返回分類名稱,在BlogController中添加API。

/// <summary>
/// 獲取分類名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("category")]
public async Task<ServiceResult<string>> GetCategoryAsync(([Required] string name)
{
    return await _blogService.GetCategoryAsync(name);
}

[Required]Attribute 指定參數name必填。

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

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

文章列表

通過分類名稱查詢文章列表和分頁查詢文章列表返回模型是一樣的,只是不用分頁,所以直接返回一個列表就可以了,添加通過分類名稱查詢文章列表和緩存的接口。

//IBlogService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name);
//IBlogCacheService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory);

分別實現這兩個接口。

//BlogCacheService.Post.cs
...
    public partial class BlogCacheService
    {
        private const string KEY_QueryPostsByCategory = "Blog:Post:QueryPostsByCategory-{0}";

        /// <summary>
        /// 通過分類名稱查詢文章列表
        /// </summary>
        /// <param name="name"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_QueryPostsByCategory.FormatWith(name), factory, CacheStrategy.ONE_DAY);
        }
    }
...
//BlogService.Post.cs
/// <summary>
/// 通過分類名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync(string name)
{
    return await _blogCacheService.QueryPostsByCategoryAsync(name, async () =>
    {
        var result = new ServiceResult<IEnumerable<QueryPostDto>>();

        var list = (from posts in await _postRepository.GetListAsync()
                    join categories in await _categoryRepository.GetListAsync()
                    on posts.CategoryId equals categories.Id
                    where categories.DisplayName.Equals(name)
                    orderby posts.CreationTime descending
                    select new PostBriefDto
                    {
                        Title = posts.Title,
                        Url = posts.Url,
                        Year = posts.CreationTime.Year,
                        CreationTime = posts.CreationTime.TryToDateTime()
                    })
                   .GroupBy(x => x.Year)
                   .Select(x => new QueryPostDto
                   {
                       Year = x.Key,
                       Posts = x.ToList()
                   });

        result.IsSuccess(list);
        return result;
    });
}

這個邏輯和分頁查詢文章列表是差不多的,聯合查詢文章表和分類表,關聯字段為CategoryId,指定查詢條件categories.DisplayName==name,以CreationTime倒序排序,年份分組,篩選出所需字段返回,在BlogController中添加API。

/// <summary>
/// 通過分類名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("posts/category")]
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByCategoryAsync([Required] string name)
{
    return await _blogService.QueryPostsByCategoryAsync(name);
}

標籤名稱&文章列表

分析:此頁面和分類頁一樣,包含兩個接口,查詢標籤的名稱和當前標籤下的文章列表。

標籤名稱

添加獲取標籤名稱接口和緩存接口,GetTagAsync()

//IBlogService.Tag.cs
/// <summary>
/// 獲取標籤名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetTagAsync(string name);
//IBlogCacheService.Tag.cs
/// <summary>
/// 獲取標籤名稱
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<string>> GetTagAsync(string name, Func<Task<ServiceResult<string>>> factory);

實現這兩個接口。

//BlogCacheService.Tag.cs
...
    public partial class BlogCacheService
    {
        private const string KEY_GetTag = "Blog:Tag:GetTag-{0}";

        /// <summary>
        /// 獲取標籤名稱
        /// </summary>
        /// <param name="name"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<string>> GetTagAsync(string name, Func<Task<ServiceResult<string>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_GetTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
        }
    }
...
//BlogService.Tag.cs
/// <summary>
/// 獲取標籤名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<string>> GetTagAsync(string name)
{
    return await _blogCacheService.GetTagAsync(name, async () =>
    {
        var result = new ServiceResult<string>();

        var tag = await _tagRepository.FindAsync(x => x.DisplayName.Equals(name));
        if (null == tag)
        {
            result.IsFailed(ResponseText.WHAT_NOT_EXIST.FormatWith("標籤", name));
            return result;
        }

        result.IsSuccess(tag.TagName);
        return result;
    });
}

FormatWith()是擴展方法,ResponseText.WHAT_NOT_EXIST是之前說過的常量,直接查詢是否存在當前name的分類,如果不存在給出錯誤提示,存在的話,則只返回分類名稱,在BlogController中添加API。

/// <summary>
/// 獲取標籤名稱
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("tag")]
public async Task<ServiceResult<string>> GetTagAsync(string name)
{
    return await _blogService.GetTagAsync(name);
}

[Required]Attribute 指定參數name必填。

文章列表

和上面一模一樣的,添加通過標籤名稱查詢文章列表接口和緩存接口。

//IBlogService.Post.cs
/// <summary>
/// 通過標籤名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name);
//IBlogCacheService.Post.cs
/// <summary>
/// 通過標籤名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <param name="factory"></param>
/// <returns></returns>
Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory);

分別實現這兩個接口。

//BlogCacheService.Post.cs
...
    public partial class BlogCacheService
    {
        private const string KEY_QueryPostsByTag = "Blog:Post:QueryPostsByTag-{0}";

        /// <summary>
        /// 通過標籤名稱查詢文章列表
        /// </summary>
        /// <param name="name"></param>
        /// <param name="factory"></param>
        /// <returns></returns>
        public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name, Func<Task<ServiceResult<IEnumerable<QueryPostDto>>>> factory)
        {
            return await Cache.GetOrAddAsync(KEY_QueryPostsByTag.FormatWith(name), factory, CacheStrategy.ONE_DAY);
        }
    }
...
//BlogService.Post.cs
/// <summary>
/// 通過標籤名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name)
{
    return await _blogCacheService.QueryPostsByTagAsync(name, async () =>
    {
        var result = new ServiceResult<IEnumerable<QueryPostDto>>();

        var list = (from post_tags in await _postTagRepository.GetListAsync()
                    join tags in await _tagRepository.GetListAsync()
                    on post_tags.TagId equals tags.Id
                    join posts in await _postRepository.GetListAsync()
                    on post_tags.PostId equals posts.Id
                    where tags.DisplayName.Equals(name)
                    orderby posts.CreationTime descending
                    select new PostBriefDto
                    {
                        Title = posts.Title,
                        Url = posts.Url,
                        Year = posts.CreationTime.Year,
                        CreationTime = posts.CreationTime.TryToDateTime()
                    })
                    .GroupBy(x => x.Year)
                    .Select(x => new QueryPostDto
                    {
                        Year = x.Key,
                        Posts = x.ToList()
                    });

        result.IsSuccess(list);
        return result;
    });
}

這個查詢有點特殊,聯合查詢了3張表,先查post_tags和tags,關聯字段TagId,再根據PostId查詢posts,指定查詢條件tags.DisplayName==name,以CreationTime倒序排序,年份分組,篩選出所需字段返回,在BlogController中添加API。

/// <summary>
/// 通過標籤名稱查詢文章列表
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[HttpGet]
[Route("posts/tag")]
public async Task<ServiceResult<IEnumerable<QueryPostDto>>> QueryPostsByTagAsync(string name)
{
    return await _blogService.QueryPostsByTagAsync(name);
}

至此,基本上完成了博客前端所需的所有查詢接口,就還剩下友鏈的查詢,大家可以自己完成,後面如果需要什麼新的接口再回頭來寫就好了。

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

搭配下方課程學習更佳 ↓ ↓ ↓

http://gk.link/a/10iQ7

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

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

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

歐洲農業政策里程碑 3900億歐元補助 只給氣候友善農民_網頁設計公司

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

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

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

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

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

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

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

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

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

背景

有人對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個考題在實際工作中的運用》這裏就不再贅述了。

 

總結

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

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

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

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

要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔_網頁設計公司

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

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

好了好了,別再說近 20 萬 Alpha 1 螢幕不能翻轉解析度又低是哪招。秉持著 One Sony 精神,Xperia 立馬就來了個同集團最強手機與相機的強強結合 — 如同預測的那樣,Xperia PRO 在具備 8K 錄影機能的 A1 發表時也隨之正式推出。將可透過 HDMI 外接的方式,成為史上最強的 4K HDR OLED 監視螢幕 — 嗯… 再加上 5G mmWave 連線應該算吧?不然… 你有看過搭載 3 主相機 + 3D iTOF 的監視器嗎!繼續閱讀要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔報導內文。

▲圖片來源:

要價近 7 萬的 Xperia PRO 正式推出:Sony Alpha 1 無反機皇最專業(DLC)拍檔

全面迎擊對手挑戰,帶來 8K 30fps 與 4K 120fps 錄影機能以及 50MP 高畫質、30fps 高速連拍,以「One」之名成為 Alpha 全片幅無反最高階存在的 A1。想不到還是承襲了 Sony 無反螢幕規格總是稍微弱了些的 DNA,甚至也沒有配上 A7S III 的全翻轉螢幕。實在是讓你有點失望?

其實 Sony 早早在去年就宣佈了配合 A1 的解決方案,將為專業而生的旗艦手機 Xperia PRO 在專業相機的發表會場合正式推出,宣布了上市資訊與相關規格。

Xperia PRO 搭載有支援超越 PCI-P3 廣色域,並與專業級 HDR 監控螢幕 Sony BVM-X300 採相同 gamut 係數的 6.5 吋 4K HDR OLED 螢幕。有望成為專業攝錄工作流程中相當輕便但強大的工具。在這次 Alpha 1 全幅無反機皇的發表會裡,Sony 也釋出其 US$2,500 的售價(!)並確認將正式在海外開賣。

既然這是台換算近 7 萬台幣的「手機」,大家應該完全可以感受到它的確並不是為一般人而來的產品。近年致力於為創作者打造核心體驗的 Sony 旗艦手機,現在,純粹為專業而生的 Xperia PRO 也進化登場。

之所以敢訂出這樣專業級的售價,Xperia PRO 自然有著專業用戶會想要買單的規格。支援觸控放大的 4K 60fps HDR 監視螢幕的用途應該不用再特別說了。它不僅可以透過 micro HDMI 外接,輸入影像進行最高 131Mbps 的串流直播,並能以 5G 毫米波搭配四組 360 度全向天線的強大連線規格全力保證通訊的穩定。

內建 3.5mm 耳機孔、雙前置揚聲器也支援杜比全景聲的它,不僅可以進行即時的影音回放,也能直接做為檔案傳輸中心,即時將內容透過 5G 傳輸至 FTP 伺服器。配合 Alpha 1 更進階的耐候規格,Xperia PRO 也擁有 IP65/68 的耐候能力,加上看起來相當強壯的機身設計,想必未來應該可以在不少專業製片領域看到它的蹤跡才是。

本篇圖片 / 引用來源

延伸閱讀:

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

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

能錄 8K 的 Sony Alpha 1 全幅無反全能機皇正式發表

M1 MacBook Air 開箱體驗:最驚喜的不變

您也許會喜歡:

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

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

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

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

【Java Spring Cloud 實戰之路】- 使用Nacos和網關中心的創建_網頁設計公司

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

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

0. 前言

在上一節中,我們創建了一個項目架構,後續的項目都會在那個架構上做補充。

1. Nacos

1.1 簡介

Nacos可以用來發現、配置和管理微服務。提供了一組簡單易用的特性集,可以快速實現動態服務發現、服務配置、服務元數據及流量管理。

Nacos用來更敏捷和容易地構建、交付和管理微服務平台。Nacos是構建以”服務“為中心的現代應用構架(例如微服務範式、雲原生範式)的服務基礎設置。

也就是通常我們所說的配置中心和服務發現中心。

1.2 搭建和啟動

Nacos目前版本不支持以Spring boot的形式創建服務,必須以一個Java包的形式單獨運行或者以Docker服務的形式運行,我們大概講解一下本地運行。

下載安裝包:

curl https://github.com/alibaba/nacos/releases/download/1.2.1/nacos-server-1.2.1.zip
unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
cd nacos/bin

使用源碼安裝:

git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/

// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

啟動:

Linux/Unix/Mac

啟動命令(standalone代表着單機模式運行,非集群模式):

sh startup.sh -m standalone

如果您使用的是ubuntu系統,或者運行腳本報錯提示[[符號找不到,可嘗試如下運行:

bash startup.sh -m standalone

Windows

啟動命令:

cmd startup.cmd

或者雙擊startup.cmd運行文件。

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

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

2. Spring Cloud Gateway

整個的網關服務,我們採用的Spring Cloud Gateway。在Spring Cloud微服務里,整個系統只對外公開了網關,其他的服務是對外不可見的。所以需要設置一個讓我們可以用的網關服務。

在 nature/manager下創建一個gateway目錄,並添加pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>club.attachie</groupId>
        <artifactId>manager</artifactId>
        <version>${revision}</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>club.attachie</groupId>
    <artifactId>gateway</artifactId>
    <packaging>jar</packaging>
    <version>${revision}</version>

</project>

在manager下註冊該模塊:

<modules>
    <module>gateway</module>
</modules>

2.1 添加 Gateway

創建完成項目后,需要添加依賴包:

<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

在gateway項目中,創建如下目錄:

├── pom.xml
└── src
    └── main
        ├── java
        │   └── club
        │       └── attachie
        │           └── gateway
        │               └── SpringGatewayApplication.java
        └── resources
            └── bootstrap.yml

創建 SpringGateAppliction.java文件,代碼如下:

package club.attachie.gateway;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;

/**
 * @author attaching
 */
@SpringBootApplication
@EnableDiscoveryClient
@RefreshScope
public class SpringGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringGatewayApplication.class, args);
    }
}

在resource目錄下創建 bootstrap.yml:

spring:
  application:
    name: gateway

yml 是Spring 的一種配置文件格式,其中名稱有application和bootstrap,bootstrap比application先加載。

2.2 添加 nacos

先在 nature/pom.xml 添加 nacos 版本號:

<nacos.version>2.2.1.RELEASE</nacos.version>

然後在dependencyManagement > dependencies 下添加 nacos相關依賴管理:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>${nacos.version}</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-starters</artifactId>
    <version>${nacos.version}</version>
</dependency>

在Gateway項目中pom.xml 添加:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

然後回過頭來,在bootstrap里設置:

spring:
  application:
    name: gateway

  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848

3 總結

nacos的配置和Gateway應用的介紹就到這裏為止了,因為個人並未對相關技術進行過多深入的研究,所以目前只能做到這些。後續研究深入了,會在這個系列中補齊的。

更多內容煩請關注我的博客《高先生小屋》

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

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

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

NVIDIA GeForce RTX 3080 Ti 實測跑分現身,效能表現幾乎跟 RTX 3090 差不多(這張還是有缺陷的工程版)_網頁設計公司

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

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

NVIDIA RTX 3000 系列自從登場以來就持續缺貨,到現在也一樣,想買都買不到,也因此不少玩家都在期待新卡。而先前曾現身 EEC 資料庫其中一張顯卡 RTX 3060,沒意外 2 月就會推出,最近終於又有另一張 RTX 3080 Ti(或稱 RTX 3080 20GB)的消息,而且還是被中國媒體搶先實測,雖然只是有瑕疵的工程版本,但整個效能表現可說讓人非常驚艷,幾乎就快跟 RTX 3090 一樣,真的是有夠香。

NVIDIA GeForce RTX 3080 Ti 實測跑分現身

近日中國 bilibili 網站的硬件大玩家頻道,上傳一部「白嫖全網首張 RTX3080Ti」的實測影片。根據說明,這張 RTX 3080 Ti 是他跟一位神秘賣家購買的,還是使用比特幣交易。他猜測有可能是從工廠偷來的,因為板子上有被打兩個洞,但已經被修復好:

板子上也沒有任何散熱器,所以他也提醒溫度測試部分可以整個忽略,因為不是很準確。另外,雖然打洞部分有被修復,但修復方式不是很穩定,因此也沒有進行超頻測試。

從 GPU-Z 截圖可以看到,中間的 RTX 3080 Ti(RTX 3080 20G)核心部分,幾乎就跟 RTX 3090 一樣,ROPs/TMUs 為 112/328,CUDA 核心共 10496 單元。不過記憶體頻寬、記憶體頻率就變成與 RTX 3080 相同:

為此,硬件大玩家也說明是因為這張工程版 RTX 3080 Ti 的記憶體少了 4 顆,頻寬少了 64bit。

首先來看 3DMark 實測分數,Time Spy Exteme 模式下,RTX 3080 Ti 僅下降了 0.99%:

Time Spy 差距也只有 1.95%:

Port Royal 也只有下降 1.69%:

Fire Strike Ultra 模式差距雖然大一點,但也僅低 2.58%:

Fire Strike Extreme 測試模式差距為 2.98%:

最後的 Fire Strike 測試分數差距最大,來到了 –7.71%:

不過整體平均來看,RTX 3080 Ti 僅比 RTX 3090 低 4.21%,非常接近:

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

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

接著是遊戲測試,這邊也先提醒一下,RTX 3080 Ti 的驅動程式是測試版本,因此跟實際一定有差異,很多遊戲也無法跑完(只有四款)。

《戰地風雲5》RTX 3080 Ti 整體表現非常接近 RTX 3090,就連時脈也跟 3090 差不多,功耗皆鎖定在 340W,

《GTA 5》也相當亮眼,幾乎跟 RTX 3090 沒有任何差距,有些場景 RTX 3080 Ti 甚至高於 RTX 3090:

《巫師 3 》測試結果跟《戰地風雲5》一樣,RTX 3080 Ti 僅略低 RTX 3090 一點:

《古墓奇兵:暗影》跟 RTX 3090 相比,平均 FPS 僅少 1FPS,一樣有著 43FPS 好表現:

硬件大玩家甚至還測試了挖礦算力,沒想到非常不錯,不僅算力達到 125.320 MH/s,功耗也只有 267W,代表說挖礦算力比 RTX 3080 還好,功耗比 RTX 3090 還要低:

不得不說這樣看下來,這張 RTX 3080 Ti 跟本又是一張神卡阿…. 他甚至透露價格可能落在 7999~8999 人民幣之間(約台幣 3.5 萬~3.9 萬),如果效能表現真是如此,那肯定又要缺貨 + 炒價了。

完整影片:

顯卡持續缺貨,中國加密貨幣礦工現在看上 RTX 3060 遊戲筆電, 挖礦效率意外的高

您也許會喜歡:

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

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

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

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

震驚!當Python遇到Excel后,將開啟你的認知蟲洞_潭子電動車

※超省錢租車方案

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

本文主要內容:   1. Excel,你為什麼如此強大 2. 軟件開發也需要團隊作戰 3. Excel的集成方案演化 4. macOS特有的集成方案:applescript 5. Python與Excel集成,有哪些好處 6. 了解多個技術領域,可以間接提高自己的IQ 7. 提高開發效率的利器:生態滲透 8. 上代碼:Python到底如何與Excel交互 9. 用Python替代VBA  
本文主要講Python與Excel的關係以及集成方案,Office家族的其他成員,如Word、PowerPoint與Excel擁有類似的功能,Python同樣可以與Word、PowerPoint等Office成員結合,這些內容我以後會寫文章講解。   我相信看這篇文章的大多數人都是程序員。在廣大程序員的眼裡,Excel以及Office家族的其他成員完全不能與Python、Java、Sprint Boot這些技術相比。Office被貼上的標籤就是:非專業人員的工具。是由那些體制內的人、會計、業務人員使用的工具,其實這是對Excel的最大誤解。

 1. Excel,你為什麼如此強大

  Excel從一問世開始,定位就是橫跨辦公和開發兩界。在上個世界末推出的Excel5.0(那時還沒有office這個產品套件)就已經支持VBA了,那可是在Win32下(一種基於dos的shell,並不屬於真正的操作系統)。儘管有些原始(以現在的眼光看),但在當時卻顯得極為先進。因為Excel(以及同期的Word)是人類史上第一個內置領域特定語言(DSL)的民用系統(可以被各個領域的人使用的系統)。正是因為有了VBA,Excel才顯得非常強大。   可能有的程序員會問,即使Excel支持VBA,可以進行編程,也只不過是完成一些自動化操作而已。VBA的功能完全不能與Python、Java、C#、C++這些被廣大程序員熟知的編程語言相比,更別說成為編程領域的主流了。沒錯,如果單憑VBA本身的確無法與這些流行的編程語言相比,但要知道,VBA和Excel本身可以與其他開發工具融合,也就是說,可以讓VBA和Excel成為自己系統的一部分,這就顯得非常牛逼了。

 2. 軟件開發也需要團隊作戰

  那麼為什麼要將Excel與其他系統結合呢?其實在我們創業時、在公司完成一個項目時,甚至在參加籃球比賽時,都會高頻率提到一個詞:團隊。 現在也流行着一句話:沒有完美的個人,只有完美的團隊。也就是說,沒有人可以什麼都會,什麼都擅長,就算是天才達芬奇也是如此。但團隊就不一樣了,即使某項工作團隊里沒人能做,也可以擴充團隊成員,吸引能做這項工作的人加入團隊。   其實在開發軟件的過程中也同樣是講究團隊作戰的。不管我們使用的開發工具有多強大,用戶社區由多龐大,都無法規避一個事實:任何技術都不可能適合完成所有的工作。 當然,還有另外一種說法就是儘管某種技術可以完成某項工作,但並不是最好的選擇。   現在回到Excel上來。首先要知道Excel擅長什麼,對,沒錯,Excel擅長表格和圖表的製作。儘管有非常多的開發工具也可以製作表格和圖表,但很顯然,Excel是其中最好的(主要用門檻、易用性、功能和用戶基數的綜合指標來衡量)。所以,如果某一個系統要求將數據轉換為表格和圖表,那麼這項任務交給Excel來完成是再合適不過了。  
3. Excel的集成方案演化   在不同的時期,Excel的集成方案也不盡相同。在Excel的大眼夾時代(那時還是Office97和Office2000的時代),微軟與開源世界還水火不容,我也還處於學生時代。在那個時代,Excel只能與Windows下的開發工具融合,其中主要的開發工具包括微軟的VC、VB、以及Borland(現在已經消失)的Delphi、C++ Builder等。     最初的集成方案有如下3種:

  • 可視方式:通過OLE組件將Excel直接嵌入窗口中,其實就相當於擁有了一個高級版的表格編輯器
  • VBA方式:通過ActiveX技術創建Excel.Applicaiton對象(一般是CreateObject函數),然後就可以任意調用VBA的API了,我比較喜歡這種方式。通過這種方式,可以將系統中的數據按着一定的格式直接傳輸到Excel中,給用戶提交的是包含表格數據的Excel文檔。
  • 反客為主方式:這種方式將Excel作為主體。也就是說,主要的操作界面是Excel,在Excel中調用或訪問其他系統。例如,很多年前我做過一個基於Excel的報表系統。該系統分別使用Delphi和Excel實現。Delphi做的管理系統,將數據發送給Excel。但需要用戶自己調整報表格式。我採用的方案是通過Excel的VBA實現表格的格式設置。其中有部分功能需要訪問SQL Server數據庫,以及完成與Delphi實現的系統類似的功能,這部分功能使用了Delphi封裝的Dll(COM組件),然後通過Excel反過來調用這些DLL。最終用戶使用的方式是用主系統完成大部分工作。如果想調整Excel的報表樣式,可以直接用Excel來完成(會在Excel上提供一些自定義的菜單和按鈕,現在通過加載項【Add-ins】實現)

  不過隨着時間的推移,現在的微軟已經擁抱開源和其他系統。所以Excel也不僅限於Windows。在macOS上也可以完成在Windows上的大多數工作,甚至Visual Studio也推出了macOS版本。而且.net core也可以同時跨Windows、macOS和Linux三個平台,SQL Server也開始支持Linux。以後我們會在更多的場景看到微軟的身影。   既然Excel已經支持了macOS平台,就需要採用跨平台的方式與Excel集成。當然,前面介紹的幾種方案現在仍然可用,但僅限於Windows平台。不過我們無法預測用戶到底使用哪一個平台,所以應該盡量使用跨平台方案。   目前主要的跨平台方案有如下3種:

  • 直接修改xlsx文件
  • 通過VBA間接調用其他編程語言
  • 使用office.js

  第1中方式有很多編程語言都支持,例如,Python、Java、Julia、Go、JavaScript。幾乎你能想到的編程語言,都有支持xlsx格式的庫。這裏只討論Python。如果想了解更多關於集成Excel的技術,可以關注我的公眾號:極客起源。   在Python語言中,支持Excel文件格式的庫非常多,如非常著名的openpyxl、xlsxwriter等。通過這些庫,可以在不依賴Excel環境的情況下,生成xlsx格式的文件。不過這些庫基本是只是生成Excel文件,並不能更好地利用VBA以及更高級的功能。由於Excel文件格式非常複雜,完全支持比較困難,所以這些庫只是支持一部分Excel的功能,但這些功能對於絕大多數需求已經足夠了。   第2種其實是一種取巧的方式,通過VBA做橋,調用其他編程語言,相當於用其他編程語言代替了VBA。這其中典型的就是xlwings。儘管這種方式從表面上看可以直接在Excel中像使用VBA一樣使用這些編程語言,但從本質上看仍然是直接寫xlsx文件。功能其實與第1種方式相同,因為這並不是官方支持的功能。   第3種是office.js,這是微軟官方提供的一個基於JavaScript的程序庫。基於Node.js,可以用JavaScript完全取代VBA實現Excel以及Office其他成員的加載項。office.js可以在Electron、Web應用以及大多數基於JavaScript的場景中使用。關於office.js的內容我以後會寫文章詳細描述,對office.js感興趣的同學也可以關注“極客起源”公眾號,會不定期更新這方面的內容。    
4. macOS特有的集成方案:applescript 除了跨平台解決方案外,在macOS上,還支持使用applescript與Office(Excel、World、PowerPoint等)交互,這些內容我以後再撰寫文章詳細講解。如果要了解excel applescript api,可以參考Excel Reference。從效果來看,applescript操作Office與在Windows下通過COM組件操作Office類似,可以完全控制Office,只是applescript的語法更接近自然語言。   下面的applescript代碼會創建一個新的Excel文檔,並將其保存為first.xlsx文件。  

 

 運行后,會看到一個打開的Excel文檔,並且已經保存為firstx.xlsx文件。

 

 5. Python與Excel集成,有哪些好處

  Excel對於Python來說,可以將Excel看做是一個可編程的大組件。這個組件的主要功能就是可以製作任意複雜的報表和圖表。儘管Python有很多模塊可以製作報表和圖表。但這些模塊的功能和效果完全沒辦法與Excel相比。所以將Python與Excel結合的最大好處是可以快速完成製作報表的任務,而且效果杠杠滴。   將Python與Excel相結合,其實還會引出另外一個思考,就是成為專家還是通才的問題。我聽到有很多程序員說,要將某種語言搞通,如PHP、Python、Java等,然後就可以很輕鬆解決所有的問題。結果真是這樣嗎?   很久以前,我聽過一個關於微軟的故事(相信很多人也聽過),在微軟有一個幾十人的團隊,花了好幾個月還沒完成一個項目,聽說是遇到了某些難題。這時有一個老程序員(據說至少50歲以上)將自己關在辦公室里一個星期,搞定! 我們先不管這個故事是真是假,那麼從理論上來說,是否有這個可能呢?其實如果光看編程速度,再牛叉的程序員,也不可能比普通程序員快幾十倍,更何況數百倍了。但還有另外一種可能,就是這名老程序員使用了完全不同的方法,繞過了大多數影響效率的因素,例如,使用了不同的工具,採用了不同的轉換方式,甚至使用了不同的設計理念等等。這就不是能力問題了,而是認知的問題。我將其稱為“認知蟲洞”。

 所謂“認知蟲洞”,是指通過某種方式很難完成某項工作,但通過另外完全不同,甚至是顛覆三觀的方式,可以用極短的時間達到目的,而且效果極好。就像找到了可以穿越浩瀚星空的蟲洞。這也有點像數學中的“等價替換”。

  可能這個微軟的例子離我們太遠,下面舉一個我自己的關於Excel例子,很多年前,我還在國內某大型軟件公司作高級程序員。團隊需要製作大量的報表,使用的主要開發工具是Delphi、後端是SQL Server數據庫。Delphi本身有自己的報表系統,叫QuickReport。功能是很強大的,但問題是,做起來太費勁。例如,要畫表格線時,如果一不小心將某根線拖到了別的地方,而且被其他東西覆蓋,那你就找把,還必須要找到,否則打印出來的表格上就會莫名其妙多了根線。結果團隊好幾個人弄了好幾天還沒弄完(也包括我)。後來我實在不想這麼弄了(因為買了幾張影碟,着急回家看電影,不想加班),於是想到了利用Excel或Word來完成這個報表系統。通過Delphi傳輸數據。   說干就干,花了不到2個小時,所有的報表全部搞定(只有我一個人哦),幾個人幾天都沒搞定的東西,我自己不到2個小時搞定,這當然不是我編程速度快了幾十倍,而是處在了不同的維度,使用了完全不同的技術來實現,用QuickReport需要一根線一根線的畫,而使用Excel,我不需要畫線,只需要用SQL語句查詢出數據,然後將這些數據發送給Excel即可。單單用了一個Excel,速度就提高了這麼多,如果系統中很多部分都使用了類似的技術,那麼編程效率提高數百倍,甚至上千倍,也不是沒有可能的。  
6. 了解多個技術領域,可以間接提高自己的IQ   可能有的同學會問,既然可以將多種技術結合起來大幅度提高開發效率,那麼為什麼不通過團隊合作的方式來完成了,通常一個人無法學會那麼多技術。其實這就是一個認知的問題,團隊合作只有在項目所採用的技術被確定后,例如,如何集成多種技術,才可以發揮作用。問題是,如果多種知識分散在不同人的大腦中,很可能沒有人意識到應該去這樣融合多種技術,就更談不上團隊合作了,就像你要探索宇宙,首先你要知道存在宇宙這種東西,否則怎麼去探索呢? 我將這種現象稱為“認知孤島”(相對於“認知蟲洞”而言),就是說並不是沒有能力去做,而是壓根就沒有意識到應該這樣做(由於知識的缺乏、同時導致想象力的受限)。   為什麼達芬奇那麼牛逼,除了聰明之外,達芬奇還橫跨多個完全不同的領域,正是因為對生物學和解刨學的了解,蒙娜麗莎的畫像才會那麼自然,栩栩如生,因為達芬奇對骨骼、肌肉的構造非常了解,這是其他任何畫家都無法比肩的。如果你在某一個領域排名前20%,而在另外一個領域排名也是前20%,那麼如果需要兩個領域的知識來解決問題時,你就會排名前4%(20% * 20%),如果是3個領域就是百里挑一。如果是6個領域,那就是萬里挑一,據說達芬奇涉足十多個領域。由於自己和自己溝通的成本為0,所以只有擁有足夠多的知識,並且有融合他們的能力,那麼你就是下一個達芬奇!

 我們可以舉個數學與Python的例子:

 如果我們的程序需要計算某個表達式的定積分(例如y = 2 * x從0到1的定積分)。    假設我們使用的是Python語言,並且不太清楚有什麼庫可以自動計算定積分,那麼採用的方式就是利用數值計算的方式寫程序去完成,計算定積分的數值計算公式比較複雜,可能不是在短時間內能完成的。不過要是了解sympy這個庫,那就是幾行代碼的事:  

import sympy
x = sympy.Symbol('x')
f = 2 * x
# 開始計算定積分
print(sympy.integrate(f,(x,0,1)))

是不是很簡單呢? 只需要了解一個API的用法就搞定了。

假設現在我們還有一個需求,要計算某個函數在某一點的導數(導數在深度學習中經常使用),而手頭又沒有必要的庫(也有可能是不知道),那麼只要了解導數的原理,就很容易通過幾行代碼搞定,這就屬於高等數學的範疇了。  

 導數原理,右側是導數的計算公式,

# 計算導數的函數
def derivative(f,x):
  h = 0.0001   # x軸的增量,需要是一個很小的值,但要在浮點數精度範圍內,通常不能超過小數點后6位
  return (f(x + h) - f(x - h)) / (2 * h)
# 待計算的函數1(y = 2 * x)  
def f1(x):
    return 2 * x
import math
# 待計算的函數2(  y = sin(x) * cos(x) / (sin(x) + cos(x))  )
def f2(x):
    return math.sin(x) * math.cos(x) / (math.sin(x) + math.cos(x))

print(derivative(f1,10))    # 1.9999999999953388
print(derivative(f2,123))   # -0.331842825692652

   PS:對這些代碼和高等數學不熟悉也沒關係,這裏我只是舉個例子,後期我會寫一些關於數學和編程方面的文章,詳細解釋這些好玩的東西,可以關注我的公眾號:極客起源 ,會不斷更新各種技術和數學文章,以及視頻課程。   從這兩個案例可以看出,在某一個領域需要非常費勁才能搞出來的東西,在另一個領域其實就是hello world。如果了解足夠多的領域,那麼完成很多工作,就會表現出天才的特徵(這也是成為天才的途徑之一,另一個途徑是投胎)。  

 PS:Excel的功能不僅僅是製作報表,Excel還擁有強大的數據分析能力。所以如果將Python與Excel集成,就意味着Python將擁有了Excel的全部能力,相當於Python擁有了Excel的整個生態。我將其稱為“生態滲透”。也就是通過集成或其他方式,一種技術可以直接或間接使用另外一種技術的全部或大部分資源。

7. 提高開發效率的利器:生態滲透    在未來,支持生態滲透的開發方式會非常普遍,如果只是用了一些現成的庫或開源軟件,並不能大幅度提高開發效率,但如果可以利用某些強大系統的生態,就不一樣了。在未來,還會有很多支持“生態滲透”的開發工具。例如,我們團隊研發的UnityMarvel,就是一款超平台開發系統。這裏之所以稱為“超平台”,而不是“跨平台”,是因為UnityMarvel不僅僅可以跨操作系統平台,還可以跨數據庫平台,雲平台、API平台、開源硬件、物聯網等,以及支持虛擬SQL、客戶端服務端一體化、柔性熱更新、Office加載項、瀏覽器插件等新特性。因此稱為“超平台”開發系統。並且自己研發了Ori編程語言(語法融合了Python、Java、Go等語言的優秀特性,但功能得到了前所未有的增強)。通過這些特性,可以用前所未有的規模利用其他系統的生態,要遠比Python使用Excel的生態更完美。其他功能先不解釋(等發布后我再寫文章詳談),先說說UnityMarvel是如何跨數據庫的。   所謂跨數據庫(目前指關係型數據, 以後會支持文檔、鍵值等NoSQL數據庫),是指用UnityMarvel開發基於數據庫的應用並不需要事先確定到底用什麼數據庫(如MySQL、SQL Server、Oracle等),UnityMarvel內置了一種虛擬數據庫,可以直接用虛擬數據庫開發,在發布時,會要求選擇使用的數據庫,例如,選擇MySQL或SQL Server。UnityMarvel會通過rosetta引擎將Ori語言的代碼轉換為支持MySQL的代碼。關於數據庫的部分,主要是用過內置的一種虛擬SQL完成的,而且這種SQL語言是與Ori語言是融為一體的。例如,如果要從persons表中查詢出id大於30的所有記錄,可以直接這樣寫:  

var  result = SELECT * FROM persons
                                 WHERE id > 30;

  result的類型是SQLSelect,將result賦給Grid組件,就會直接显示查詢結果。當發布時,會將上面的代碼轉換為使用相應數據庫(如MySQL、SQL Server)的特定編程語言(如JavaScript、Java等)的代碼。這麼做的好處如下: 1. 不需要進行數據庫選型,數據庫是在發布時後期綁定的; 2. 如果想切換數據庫(例如,從MySQL換成Oracle),只需要重新發布,選擇相應的數據庫就可以了,不需要修改一行代碼; 3. 統一數據庫接口,開發人員並不需要了解各種數據庫的細節,開發門檻低; 4. UI與數據庫交互非常容易,不必考慮各種數據庫引擎和庫,只需要直接將SQL語句賦給與其交互的UI組件即可; 5. 自動檢測和去除大多數SQL中的潛在風險,如SQL注入等; 6. 脫離數據庫環境開發。例如,想使用MySQL數據庫開發,但當前機器上並沒有MySQL開發環境,又不想安裝MySQL。這時仍然可以用UnityMarvel內置的虛擬數據庫進行開發,然後發布即可,部署在有MySQL環境的機器上就可以成功運行了;  

 

 

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

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

8. 上代碼:Python到底如何與Excel交互   在這一節玩點真格的,看一看Python到底如何與Excel交互。我們使用目前最常用的openpyxl來完成操作。先看一個未處理的Excel表格。

 

 

 上面這個表格是關於營業計劃的數據,看起來很彆扭,因為不同層次的數據之間沒有縮進,也沒有背景顏色,甚至沒有表格線。如果要將這個表格交給領導,估計領導會拿起塊磚頭砸過來!   領導最希望見到下面的表格:

 這個表格看起來是不是很舒服呢!其實這個表格用Excel做起來也並不費勁。不過仍然需要N步,這裏就不詳細解釋如何用Excel來做這個表格了,現在來看如何利用Python閃電般進行格式轉換。

from openpyxl.styles import Alignment,Font,Border,Side,Color,PatternFill
import openpyxl
# 打開待轉換的文件
workbook = openpyxl.load_workbook('原始表格.xlsx')

ws = workbook.active
table = ws['A1':'D11']
# 設置字體
ft = Font(name="黑體")
for rows in table:
    for cell in rows:
        cell.font = ft
# 調整行高(所有的行的高度統一設置為18)
for i in range(1,ws.max_row + 1):
    ws.row_dimensions[i].height = 18.0
# 插入列
ws.insert_cols(1,1)

# 調整新插入列的寬度
ws.column_dimensions['A'].width = 5

# 插入行
ws.insert_rows(1,1)
# 調整新插入行的高度
ws.row_dimensions[1].height = 10


# 文字左對齊,数字右對齊
leftAlign = Alignment(horizontal='left',vertical='center')
rightAlign = Alignment(horizontal='right',vertical='center')
for row in ws.rows:
    for cell in row:
        # 数字,右對齊
        if type(cell.value) == int:
            cell.alignment = rightAlign
        else:
            cell.alignment = leftAlign

# 調整列寬
ws.column_dimensions['B'].width =20
ws.column_dimensions['C'].width =9
ws.column_dimensions['D'].width =9
ws.column_dimensions['E'].width =9
ws.column_dimensions['F'].width =4  # 讓表格線出來一點



# 為表格添加邊框

topBorder = Border(top=Side(border_style='thick',color='000000'))
                #bottom=Side(border_style='thick',color='000000'),
                #horizontal = Side(border_style='thin',color='000000'))
# 添加表格頂邊的粗線(包括最後沒有數據的列)
for col in range(2, ws.max_column + 2):
    ws.cell(2, col).border = topBorder

bottomBorder = Border(bottom=Side(border_style='thick',color='000000'))
# 添加表格底邊的粗線(包括最後沒有數據的列),這裏需要加1,是因為前面繪製表格頂邊的粗線時,最大列的數量已經多了1個
# 所以只需要加1即可
for col in range(2, ws.max_column + 1):
    ws.cell(ws.max_row, col).border = bottomBorder

# 添加水平細線
horizontalBorder = Border(top=Side(border_style='thin',color='000000'))
for col in range(2, ws.max_column + 1):
    for row in range(4,ws.max_row):
        ws.cell(row, col).border = horizontalBorder

# 單元格縮進
ws['B5'].alignment=Alignment(indent=1)
ws['B6'].alignment=Alignment(indent=1)
ws['B8'].alignment=Alignment(indent=1)
ws['B11'].alignment=Alignment(indent=1)

ws['B9'].alignment=Alignment(indent=2)
ws['B10'].alignment=Alignment(indent=2)

# 設置文字顏色
blueFont = Font(name="Arial",color = '4169E1')
for col in range(3, ws.max_column + 1):
    ws.cell(5, col).font= blueFont
    ws.cell(6, col).font = blueFont
    ws.cell(9, col).font = blueFont
    ws.cell(10, col).font = blueFont
# 設置背景色
fill = PatternFill("solid", fgColor="B0C4DE")
for col in range(2, ws.max_column + 1):
    ws.cell(4, col).fill= fill
    ws.cell(7, col).fill = fill
    ws.cell(12, col).fill = fill

workbook.save('轉換后的表格.xlsx')

print('見證奇迹的時刻')

 

現在運行程序,當輸出“見證奇迹的時刻”后,就會在當前目錄生成一個“轉換后的表格.xlsx”,該文件就是上圖的效果,是不是很神奇呢?   從這段程序中可以看出,轉換該表格需要多少步,代碼並不複雜,大家可以根據openpyxl的文檔研究。  
9. 用Python替代VBA   目前微軟官方還沒有將Python作為VBA的替代品,倒是將JavaScript作為了另外一個選擇(office.js),不過可以利用xlwings做一個折中。xlwings可以單獨使用,也可以通過xlwings office加載項提供的RunPython函數運行Python代碼。   現在有一個hello.py文件,代碼如下:  

import xlwings as xw
def hello_xlwings():
    wb = xw.Book.caller()
    wb.sheets[0].range("A1").value = "Hello xlwings!"

  在xlwings的安裝目錄有一個xlwings.xlam文件,該文件是Excel的加載項文件,也就是Excel VBA的發行包文件。現在隨便開啟一個空的Excel workbook,然後點擊“工具”>“Excel加載項”菜單項,會打開如下圖所示的對話框,找到xlwings.xlam文件,並選中該文件。

 

 然後在“開發工具”選項卡中點擊“Visual Basic”按鈕(如下圖所示),進入VBA編輯頁面。

 

 

 最後引用xlwings庫即可。

  現在可以新建一個VBA模塊,然後編寫下面的代碼:  

 Sub test()
     RunPython ("import  hello; myproject.hello_xlwings()")
 End Sub   

運行腳本,就會看到在“A1”的位置插入了Hello xlwings!

  OK,現在大家已經了解了如何使用Python與Excel交互,其他還有很多種方法,而且也不僅僅只有Python能與Excel交互,其實幾乎所有的編程語言,甚至是C語言,都有想用的Library可以與Excel交互。那就期待我下面的文章吧!    

 

 

   

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

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

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

OPPO Find X3 Pro 實機上手玩照片曝光:火山口設計主相機,並加入顯微鏡拍攝_網頁設計公司

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

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

傳聞將於 3 月登場的 OPPO Find X3 系列中備受矚目的 Find X3 Pro ,在前段時間來自 Evan Blass(evleaks)首曝過官方渲染圖,讓大家對於這款新機有了初步的概念。而今日稍早, evleaks 更是直接洩漏多張 OPPO Find X3 Pro 的實機外觀照片,從這批照片可以發現其實和之前的渲染圖幾乎吻合,不過實機的樣貌看起來還是相當特殊。

▲圖片來源:Evan Blass(Voice/@evleaks)

OPPO Find X3 Pro 實機上手玩照片曝光:火山口設計主相機,並加入顯微鏡拍攝

除了日前電腦王阿達為大家開箱的 OPPO Reno5/Reno5 Pro 開箱,相信也有不少人等待 2021 年 OPPO 在全新 Find X 系列會帶來哪些驚喜。稍早,爆料大神 Evan Blass(evleaks)釋出多張 Find X3 Pro 的實機外觀照片,與他之前分享的渲染圖的外觀造型可說是幾乎相同。這款將搭載 Qualcomm Snapdragon 888 的 Find X3 Pro 在機身背面和相機模組間有著流線的曲面弧度,而相機模組周圍微微隆起的「火山口」設計,據傳 Find X3 Pro 將推出玻璃和陶瓷兩種材質版本,相信對於生產也將帶來相當大的挑戰。

▲圖片來源:Evan Blass(Voice/@evleaks)

▲圖片來源:Evan Blass(Voice/@evleaks)

▲圖片來源:Evan Blass(Voice/@evleaks)

相機規格方面, Find X3 Pro 傳聞將搭載 5000 萬像素四鏡頭主相機的配置,其中包括 5000 萬像素的主鏡頭和超廣角鏡頭(SONY IMX766 感光元件),另外最特殊的是 Find X3 Pro 將加入一枚配有環形補光燈的 300 萬像素微距鏡頭,其 25 倍變焦可實現「顯微鏡」模式拍攝。至於第四顆鏡頭,則是去年就在 Find X2 搭載的 1300 萬像素 2x 長焦鏡頭( F2.4光圈、5P 鏡頭、5 倍混合變焦、最高 20倍數位變焦)。

▲圖片來源:Evan Blass(Voice/@evleaks)

在一月底,數碼閒聊站也在微博刊出一張手機的相機操作介面截圖,當時就曾出現過「顯微鏡」模式:

▲圖片來源:數碼閒聊站(微博)

最後關於 Find X3 系列發表的時間,傳聞 OPPO 有望於三月正式發表全新 Find X3 系列,包括 Find X3 Pro 、 Find X3 Neo 以及 Find X3 Lite ,其中 Find X3 Lite 日前的開箱照也證實就是台灣已推出的 Reno5 的更名版本。

消息來源:Evan Blass(Voice/@evleaks)|數碼閒聊站(微博)

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

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

延伸閱讀:
OPPO Find X3 Pro 更多關鍵規格曝光:將搭載高通 S888 處理器、12GB RAM、256GB ROM

ROG Phone 5 更多外觀、規格細節曝光:另有 Anime Matrix 顯示版本?

您也許會喜歡:

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

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

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

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

想買熱銷國產SUV?看車主和教授怎麼說

長安CS75的外觀上,也真能夠與哈弗H6相比了,相信大部分人都會覺得時尚好看,前大燈上的日間行車燈與寶馬的天使眼有異曲同工之處,配置上基本上也配備了ESp車身穩定系統,發動機啟停裝置,多功能方向盤等等。動力上隨着前段時間上市的1。

據9月份的數據統計,我國SUV市場銷量達到了88萬輛,從這2天剛公布的10月份SUV銷量數據中,銷量數據也持續上升,截止至9月份,今年1-9月在我國的SUV市場銷量就達到了600萬輛,比去年增加了百分之46%!這些表現都超出了預期的数字,我和我的小夥伴都驚呆了,既然大家那麼熱衷地購買SUV,迫不及待地想知道,究竟是哪些車型車企帶來這麼好的銷售成績。

從汽車行業批發數據中,我們能看到從1-9月份在我國SUV銷量排名的車企前五名分別是:長城汽車,長安汽車,上汽通用,東風日產和北京現代。其中長城汽車以59萬輛的超高銷量數據優勢位居榜首,在其中的哈弗H6可幫了不少忙呀,長安汽車也依靠着CS75和CS35的銷量之力衝上了第二名。

看完這一大波數據后,又特么鬱悶了,為何銷量冠軍永遠都是哈弗H6,且10月份還賣了56667輛,是個相當不錯的領先成績,而第二名則是還是傳祺GS4,第三名為寶駿560,第四名為別克昂科威,在這幾個月的銷量中,別克昂科威也正在逐步拉近與寶駿560的銷量成績,有可能位居第三。

那麼這些月銷近百萬輛的SUV,到底是誰的功勞?

三大企業月銷量圖

從SUV的銷量成績上看,目前我國功勞最大的三家自主車企應該是:長城汽車,長安汽車和吉利汽車,究竟是哪些具體SUV車型為其帶來如此大的銷量,它們又都有什麼消費者看中的優勢,且聽一個一個分析給大家聽聽。

長城汽車

在10月份中長城汽車累計銷量達到了104844輛,已經突破10萬大軍!其中銷量最好的車型有獨挑大梁的哈弗H6(10月份銷量56667輛)和哈弗H2(10月份銷量21079輛)。在中國SUV的領域里,目前還未出現車型接近哈弗H6銷量的車型,即便是小型SUV的哈弗H2,銷量也僅僅是H6車型的一半,看來長城SUV自主品牌已經樹立了根深蒂固的品牌形象,在今年銷量中很難被超越。

對於銷量神車級別的哈弗H6,很多人都在疑問着為什麼可以賣得這麼好?究竟有什麼產品實力,判斷一輛車無非有這麼幾個因素,外觀,動力,配置,價格。在中國如果將一輛汽車外觀設計得非常美,非常符合絕大多數人的審美觀,那是不可能的,所以哈弗H6外觀中庸,這就很好地照應了廣大消費者的需求,然而在配置上除了最低配的沒有配備ESp車身穩定系統之外,剩餘的車型基本都配備了很多實用保命配置如ESp,胎壓監測,倒車雷達,無鑰匙進入,天窗等等,價格呢非常便民,10萬起步,要的東西,基本都會有了,空間寬敞,底盤紮實。

雖然說哈弗H2在小型SUV市場里的總銷量剛好被長安CS35超過,不過在10月份銷量中仍然保持前列,藉著長城汽車的名號,H2的關注度很非常高,內飾做工沒得說,中控上採用的軟性塑料,做工精細,配置豐富,乘坐空間也能讓人滿意,油耗方面相比H6肯定有所降低,大概每百公里油耗為6.7升油。

長安汽車

根據最新銷售數據显示,長安汽車在10月份中有6款產品單月銷量突破1萬輛,成為中國品牌單個車型銷量過萬最多的車企,不管是轎車還是SUV,銷量數據都相對平均,全部車型的銷量加起來已經突破了11萬輛大軍,CS75銷量重回2萬輛以上,CS35表現穩定,當月銷量17583輛,且小型SUV的CS15銷量也已經逼近1萬輛,剩餘的車型包括逸動,悅翔系列,CX70,歐諾和歐尚,每款車型的單月銷量皆突破1萬輛,長安汽車確實每款車型都能夠深入人心啊。

長安CS75的外觀上,也真能夠與哈弗H6相比了,相信大部分人都會覺得時尚好看,前大燈上的日間行車燈與寶馬的天使眼有異曲同工之處,配置上基本上也配備了ESp車身穩定系統,發動機啟停裝置,多功能方向盤等等。動力上隨着前段時間上市的1.5T車型外,還有着1.8T和2.0L兩種規格,豐富了動力範圍,懸挂濾震的程度還是蠻好的,雖然操控上不是很好,但它始終是一台SUV,乘坐舒適就夠了。

長安CS35算是小型SUV里的一名老將,一直保持不錯的銷量成績,雖然尺寸不大但空間不小,2560mm的軸距表示不甘示弱,依然能夠達到同級別的主流水平,內飾做工方面雖然不見得比哈弗H2好多少,但中控分佈按鍵也非常簡單實用,配置雖然不算高但卻很實用,大部分車型配備ESp車身穩定裝置,真皮多功能方向盤,天窗,倒車雷達等等。懸挂舒適偏軟可以接受,動力1.5T也非常足夠。

吉利汽車

吉利汽車在10月份的車型總銷量達到96158輛,距離10萬大軍還差那麼一點,其實吉利在2014年的時候,銷量並不是很樂觀,但是在這兩年的時間里,博越,遠景SUV和帝豪GS的上市,款款都是爆款,慢慢地為吉利汽車貢獻了不少銷量成績,其中在10月份博越賣出了16779輛(由於產能問題,還有很多人下了訂單仍然在排隊提車),遠景SUV賣出了10867輛,帝豪GS賣出了10028輛,所以在SUV里,可以說吉利發展得比長城和長安更加均衡。

繼中國最美轎車的吉利博瑞之後,吉利又出一爆款博越,由於產能問題,至今經銷商手上還有許多客戶訂單在排隊購車,確實,比起哈弗H6和長安CS75來說,吉利博越車頭採用水滴漣漪格柵,這已經俘獲了許多消費者的心,全新樣式的尾燈配合雙邊共出樣式的排氣管,整輛車更有動感,同時在配置上博越還是國內首款支持蘋果Carplay的中國品牌SUV,內部科技感十足,更有一鍵啟動,定速巡航,自動空調,ESp,电子手剎,自動駐車等豐富實用配置,確實是10萬出頭的價格,能夠買到20萬級別的享受。

吉利汽車新推出的遠景SUV,搭載了低排量1.3T渦輪增壓發動機,能夠保證大動力輸出的同時將油耗降低下來,除此之外還有1.8L自然吸氣發動機,配置上不能說是豐富,簡直都是全系標配ESp車身穩定系統,上坡輔助,陡坡緩降和真皮方向盤等等,新車上市有幾個月,目前接到車主們的投訴非常少,所以還可靠性還是蠻高的。

帝豪GS上的動力總成與遠景SUV一樣,同樣有着低排量的1.3T渦輪增壓和1.8L自然吸氣發動機,但是在匹配傳輸上,帝豪GS採用的是手動擋和雙離合變速器,而遠景SUV則是手動擋和CVT無級變速器,所以用戶們可以依靠自己喜好去選擇車輛,配置都挺齊全。

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準

視頻處理之OSD

欲觀原文,請君移步

OSD簡介

OSD,on-screen display的簡稱,即屏幕菜單式調節方式。一般我們按一下Menu鍵后屏幕彈出的显示器各項調節項目信息的矩形菜單,比如調亮度,色調,飽和度等信息,這個显示這個菜單的功能就是視頻行業的OSD。

基於FPGA的OSD設計與實現

1 Xilinx OSD IP功能

  • 支持最多8個layer
  • 背景顏色可編程
  • 位置,大小,顏色,透明度(alpha)可編程
  • 支持RGB和YUV視頻流

2 硬件結構框圖

硬件平台是基於xilinx xc7z035芯片開發的,關鍵模塊框圖如下圖1所示。

  • 一個時序產生模塊Video Timing Controller(在本次實驗中採用1080P標準時序)

  • 首先PL端將視頻流通過VDMA讀出,輸出接口為AXI4-Stream的數據流

  • 然後視頻流進入OSD IP(OSD輸入輸出也是AXI4-Stream接口)

  • 最後OSD輸出數據流與1080P時序同時送入到AXI4-Stream to Video Out模塊,輸出為HDMI接口

下面小編會詳細介紹OSD IP的例化與使用

3 OSD PL端

如果在使用OSD IP過程中出現如下錯誤,請在xilinx官網上申請OSD的License,這裏不再詳述如何申請License。

首先在Block Design中加入Video On Screen Display,打開後會看到如下圖2。

(1) 勾選AXI-Lite Interface:PS端通過AXI-Lite進行配置該IP

(2) Video Format選擇RGB

(3) Layers選擇2

(4) Layer Configuration:LAYER0選擇外部視頻流,也就是實時視頻,LAYER1選擇Internal,PS端可以控制進行圖文疊加

點擊Screen Layout Options,如圖3所示

(1) Background size(選擇背景大小)里寬度輸入1920,高度輸入1080

(2) Background color輸入背景顏色,這裏選擇黑色,可以通過axi-lite來控制

(3) layer0因為選擇的是外部視頻流,所以比如設置為外部視頻流分辨率,輸錯了,可能無法正常使用,小編已經遇到過了,本文使用1920×1080外部視頻流

(4) layer1因為選擇的是內部圖像控制器,所以無所謂設置什麼,可以通過axi-lite控制,所以選擇默認即可

點擊LAYER 1 Options出現圖4界面:因為是內部圖像控制器,所以可以進行一些配置,比如顏色多少,字符數目,比特像素等等,這裏小編選擇的是默認。

配置完OSD IP后,將其AXI-lite掛在總線上即可,然後保存Block Design即可。

注:點開Address Editor,一定要確定該IP被分配地址空間,如果沒有,點擊一下自動分配(小編遇到的問題就是這個ip地址空間在unmap里,導致後續PS端OSD IP無法初始化)。

4 OSD PS端

下面就是常規操作include bitstream導出SDK,其實就是生成hdf文件,硬件信息。然後就launch SDk。如圖4所示,可以看到hdf文件里都有什麼。

新建一個design_top的空工程,如圖5所示,在design_top_bsp下面可以看到system.mss文件,在紅框中找到OSD IP。

點擊import examples,出現如圖6所示,勾選對話框后選擇OK(不會玩IP先整個example)。

打開XosdSelfTestExample.c即可看到該例子程序是怎麼個處理流程(圖7為main函數,圖8為使用流程)小編稱之為PS端IP使用三步法

  • 第一步先進行lookup該IP

  • 第二步就是初始化該IP

  • 第三步就是使用IP

運行一下,結果如圖9所示,可以看到UART會打印OSD成功信息。

OSD 實例

閑話不說,上面經過了OSD example,小編也作為一個PS端初學者來玩一玩。

尷尬的是經常在寫c代碼的時候想着寫begin…end,真是verilog寫習慣了,思想難以改變,原來是花括弧啊{}

初始化模塊如下

在初始化后必須將該模塊進行複位,然後,否則該IP啟動不了。

int OsdInit(int DeviceID)
{
	int Status;
	/* Initialize the OSD instance */
	OsdCfgPtr = XOSD_LookupConfig(DeviceID);
	Status = XOSD_CfgInitialize(&Osd, OsdCfgPtr,OsdCfgPtr->BaseAddress);
	if (Status != XST_SUCCESS)		return 1;
	/* Reset the devices */
	XOSD_Reset(&Osd);
	/* Enable the OSD device and tell it to pick up the register changes	*/
	XOSD_Enable(&Osd);
	XOSD_RegUpdateEnable(&Osd);
	return 0;
}

配置模塊

這裏需要注意的是把BANKIndex輸入為1,否則會進行字符填寫方式就需要改變,不符合操作習慣XOSD_LoadCharacterSetBank(&Osd, Gcindex, 1, (u32 *)Font);

void Graphics_setting(u8 Gcindex,u8 LayerPriority,u32 ColorData[],u32 *TextData)
{
	int width = 1920;
	int height = 1080;
	int LayerAlphaValue = 0xFF;
	int LayerGlobalAlphaEnable = 0;
	XOSD_SetLayerAlpha(&Osd, Gcindex, LayerGlobalAlphaEnable,LayerAlphaValue);
	XOSD_SetLayerPriority(&Osd, Gcindex, LayerPriority);
	XOSD_SetLayerDimension(&Osd, Gcindex, 0, 0, width, height);
	XOSD_EnableLayer(&Osd, Gcindex);
	/* Load color, font and text and set the active banks */
	XOSD_LoadColorLUTBank(&Osd, Gcindex, 0, ColorData);
	//set BankIndex is 1(fit our keyboard)
	XOSD_LoadCharacterSetBank(&Osd, Gcindex, 1, (u32 *)Font);
	XOSD_LoadTextBank(&Osd, Gcindex, 0, (u32 *)TextData);
	XOSD_SetActiveBank(&Osd, Gcindex, 0, 0, 0, 0);
}

圖文疊加模塊

void OsdDrawText(int Gcindex,int x_pos, int y_pos, int color, int string_index, int text_size)
{
	u32 Instruction[XOSD_INS_SIZE];
	u16 ObjType = XOSD_INS_OPCODE_BOXTXT; /* A text string 	XOSD_INS_OPCODE_TXT*/
	u8 ObjSize = (text_size<<4); /* Text Scale factor (1x, 2x, 4x, 8x)	*/
	u16 XStart = x_pos; /* Horizontal start pixel of the text	*/
	u16 YStart = y_pos; /* Vertical start line of the text */
	u16 XEnd = x_pos; /* Horizontal end pixel of the text (not	used) */
	u16 YEnd = y_pos; /* Vertical end line of the text (must be same as YStart) */
	u8 TextIndex = string_index; /* Index of Text String */
	u8 ColorIndex = color; /* Color used to draw text */


	XOSD_CreateInstruction(&Osd, Instruction, Gcindex,ObjType, ObjSize,	XStart, YStart, XEnd, YEnd,TextIndex, ColorIndex);
	XOSD_LoadInstructionList(&Osd, Gcindex, 0, Instruction, 1);
	return;
}

實現結果

前面只給出了兩個圖層,工程退不回去了,目前工程實現的是疊加8個圖層(1個視頻,7個內部圖像控制器)。

參考鏈接

百度網盤源碼以及參考文檔鏈接如下

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

【其他文章推薦】

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

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

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

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

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

※超省錢租車方案

※回頭車貨運收費標準