1. 程式人生 > >ABP入門系列(8)——Json格式化

ABP入門系列(8)——Json格式化


講完了分頁功能,這一節我們先不急著實現新的功能。來簡要介紹下Abp中Json的用法。為什麼要在這一節講呢?當然是做鋪墊啊,後面的系列文章會經常和Json這個東西打交道。

一、Json是幹什麼的

JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。 易於人閱讀和編寫。同時也易於機器解析和生成。JSON採用完全獨立於語言的文字格式,但是也使用了類似於C語言家族的習慣(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 這些特性使JSON成為理想的資料交換語言。

Json一般用於表示:
名稱/值對
{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"}


陣列
`{ "people":[ {"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"}, {"firstName":"Jason","lastName":"Hunter","email":"bbbb"}, {"firstName":"Elliotte","lastName":"Harold","email":"cccc"} ] }

二、Asp.net Mvc中的JsonResult

Asp.net mvc中預設提供了JsonResult來處理需要返回Json格式資料的情況。
一般我們可以這樣使用:

public ActionResult Movies()
{
    var movies = new List<object>();

    movies.Add(new { Title = "Ghostbusters", Genre = "Comedy", ReleaseDate = new DateTime(2017,1,1)  });
    movies.Add(new { Title = "Gone with Wind", Genre = "Drama", ReleaseDate = new DateTime(2017, 1, 3) });
    movies.Add(new { Title = "Star Wars", Genre = "Science Fiction", ReleaseDate = new DateTime(2017, 1, 23) });

    return Json(movies, JsonRequestBehavior.AllowGet);
}

其中Json()是Controller基類中提供的虛方法。
返回的json結果格式化後為:

[
  {
    "Title": "Ghostbusters",
    "Genre": "Comedy",
    "ReleaseDate": "\/Date(1483200000000)\/"
  },
  {
    "Title": "Gone with Wind",
    "Genre": "Drama",
    "ReleaseDate": "\/Date(1483372800000)\/"
  },
  {
    "Title": "Star Wars",
    "Genre": "Science Fiction",
    "ReleaseDate": "\/Date(1485100800000)\/"
  }
]

仔細觀察返回的json結果,有以下幾點不足:

  • 返回的欄位大小寫與程式碼中一致。這就要求我們在前端中也要與程式碼中用一致的大小寫進行取值(item.Titleitem.Genreitem.ReleaseDate)。
  • 不包含成功失敗資訊:如果我們要判斷請求是否成功,我們要手動通過獲取json資料包的length獲取。
  • 返回的日期未格式化,在前端還需自行格式化輸出。

三、Abp中對Json的封裝

所以Abp封裝了AbpJsonResult繼承於JsonResult,其中主要添加了兩個屬性:

  • CamelCase:大小駝峰(預設為true,即小駝峰格式)
  • Indented :是否縮排(預設為false,即未格式化)

並在AbpController中過載了ControllerJson()方法,強制所有返回的Json格式資料為AbpJsonResult型別,並提供了AbpJson()的虛方法。

/// <summary>
/// Json the specified data, contentType, contentEncoding and behavior.
/// </summary>
/// <param name="data">Data.</param>
/// <param name="contentType">Content type.</param>
/// <param name="contentEncoding">Content encoding.</param>
/// <param name="behavior">Behavior.</param>
protected override JsonResult Json(object data, string contentType, 
    Encoding contentEncoding, JsonRequestBehavior behavior)
{
    if (_wrapResultAttribute != null && !_wrapResultAttribute.WrapOnSuccess)
    {
        return base.Json(data, contentType, contentEncoding, behavior);
    }

    return AbpJson(data, contentType, contentEncoding, behavior);
}

protected virtual AbpJsonResult AbpJson(
    object data,
    string contentType = null,
    Encoding contentEncoding = null,
    JsonRequestBehavior behavior = JsonRequestBehavior.DenyGet,
    bool wrapResult = true,
    bool camelCase = true,
    bool indented = false)
{
    if (wrapResult)
    {
        if (data == null)
        {
            data = new AjaxResponse();
        }
        else if (!(data is AjaxResponseBase))
        {
            data = new AjaxResponse(data);
        }
    }

    return new AbpJsonResult
    {
        Data = data,
        ContentType = contentType,
        ContentEncoding = contentEncoding,
        JsonRequestBehavior = behavior,
        CamelCase = camelCase,
        Indented = indented
    };
}

在ABP中用Controler繼承自AbpController,直接使用return Json(),將返回Json結果格式化後:

{
  "result": [
    {
      "title": "Ghostbusters",
      "genre": "Comedy",
      "releaseDate": "2017-01-01T00:00:00"
    },
    {
      "title": "Gone with Wind",
      "genre": "Drama",
      "releaseDate": "2017-01-03T00:00:00"
    },
    {
      "title": "Star Wars",
      "genre": "Science Fiction",
      "releaseDate": "2017-01-23T00:00:00"
    }
  ],
  "targetUrl": null,
  "success": true,
  "error": null,
  "unAuthorizedRequest": false,
  "__abp": true
}

其中result為程式碼中指定返回的資料。其他幾個鍵值對是ABP封裝的,包含了是否認證、是否成功、錯誤資訊,以及目標Url。這幾個引數是不是很sweet。
也可以通過呼叫return AbpJson()來指定引數進行json格式化輸出。

仔細觀察會發現日期格式還是怪怪的。2017-01-23T00:00:00,多了一個T。檢視AbpJsonReult原始碼發現呼叫的是Newtonsoft.Json序列化元件中的JsonConvert.SerializeObject(obj, settings);進行序列化。

檢視Newtonsoft.Json官網介紹,日期格式化輸出,需要指定IsoDateTimeConverterDateTimeFormat即可。

IsoDateTimeConverter timeFormat = new IsoDateTimeConverter();
            timeFormat.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";

JsonConvert.SerializeObject(dt, Formatting.Indented, timeFormat)

那在我們Abp中我們怎麼去指定這個DateTimeFormat呢?
ABP中提供了AbpDateTimeConverter類繼承自IsoDateTimeConverter
但檢視ABP中整合的Json序列化擴充套件類:

public static class JsonExtensions
  {
    /// <summary>Converts given object to JSON string.</summary>
    /// <returns></returns>
    public static string ToJsonString(this object obj, bool camelCase = false, bool indented = false)
    {
      JsonSerializerSettings settings = new JsonSerializerSettings();
      if (camelCase)
        settings.ContractResolver = (IContractResolver) new CamelCasePropertyNamesContractResolver();
      if (indented)
        settings.Formatting = Formatting.Indented;
      settings.Converters.Insert(0, (JsonConverter) new AbpDateTimeConverter());
      return JsonConvert.SerializeObject(obj, settings);
    }
  }

明顯沒有指定DateTimeFormat,那我們就只能自己動手了,具體程式碼請參考4種解決json日期格式問題的辦法的第四種辦法。

當有異常發生時,Abp返回的Json格式化輸出以下結果:

{
  "targetUrl": null,
  "result": null,
  "success": false,
  "error": {
    "message": "An internal error occured during your request!",
    "details": "..."
  },
  "unAuthorizedRequest": false
}

當不需要abp對json進行封裝包裹怎麼辦?
簡單。只需要在方法上標記[DontWrapResult]特性即可。這個特性其實是一個快捷方式用來告訴ABP不要用AbpJsonResult包裹我,看原始碼就明白了:

namespace Abp.Web.Models
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)]
    public class DontWrapResultAttribute : WrapResultAttribute
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DontWrapResultAttribute"/> class.
        /// </summary>
        public DontWrapResultAttribute()
            : base(false, false)
        {

        }
    }
    
    /// <summary>
    /// Used to determine how ABP should wrap response on the web layer.
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method)]
    public class WrapResultAttribute : Attribute
    {
        /// <summary>
        /// Wrap result on success.
        /// </summary>
        public bool WrapOnSuccess { get; set; }

        /// <summary>
        /// Wrap result on error.
        /// </summary>
        public bool WrapOnError { get; set; }

        /// <summary>
        /// Log errors.
        /// Default: true.
        /// </summary>
        public bool LogError { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="WrapResultAttribute"/> class.
        /// </summary>
        /// <param name="wrapOnSuccess">Wrap result on success.</param>
        /// <param name="wrapOnError">Wrap result on error.</param>
        public WrapResultAttribute(bool wrapOnSuccess = true, bool wrapOnError = true)
        {
            WrapOnSuccess = wrapOnSuccess;
            WrapOnError = wrapOnError;

            LogError = true;
        }
    }
}

AbpResultFilterAbpExceptionFilter過濾器中會根據WrapResultAttributeDontWrapResultAttribute特性進行相應的過濾。

四、Json日期格式化

第一種辦法:前端JS轉換:

    //格式化顯示json日期格式
    function showDate(jsonDate) {
        var date = new Date(jsonDate);
        var formatDate = date.toDateString();
        return formatDate;
    }

第二種辦法:在Abp的WepApiModule(模組)中指定JsonFormatter的時間序列化時間格式。

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.DateFormatString ="yyyy-MM-dd HH:mm:ss";

PS:這種方法僅對WebApi有效。

總結

本節主要講解了以下幾個問題:

  1. Asp.net中JsonResult的實現。
  2. ABP對JsonResult的再封裝,支援指定大小駝峰及是否縮排進行Json格式化。
  3. 如何對DateTime型別物件進行格式化輸出。
  • Web層通過拓展AbpJsonResult,指定時間格式。
  • 前端,通過將Json日期轉換為js的Date型別,再格式化輸出。
  • WebApi,通過在Moduel中指定DateFormatString。

相關推薦

ABP入門系列8——Json格式化

講完了分頁功能,這一節我們先不急著實現新的功能。來簡要介紹下Abp中Json的用法。為什麼要在這一節講呢?當然是做鋪墊啊,後面的系列文章會經常和Json這個東西打交道。 一、Json是幹什麼的 JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式。 易於人閱讀和編寫

Android GIS開發系列-- 入門8 Json與Geometry的相互轉換

相互轉換 them 實用 興趣 parse 執行 pretty pre andro 在Android中json數據十分普遍,也很實用,在Arcgis中也同樣支持Json數據,Json與Geometry可以相互轉換,達到我們想要的數據。 一、Geometry轉換成Json數

arcgis jsapi介面入門系列8:滑鼠在地圖畫面

初始化,每個map執行一次 PS:畫點也差不多,都是用SketchViewModel,因此本demo沒有專門寫畫點的 drawPolygonInit: function () { //畫幾何物件初始化 //新建一個圖形圖

ABP入門系列12——如何升級Abp並除錯原始碼

1. 升級Abp 本系列教程是基於Abp V1.0版本,現在Abp版本已經升級至V1.4.2(截至至文章釋出時間),其中新增了New Feature,並對Abp做了相應的Enhancements,以及Bug fixs。現在我們就把它升級至最新版本,那如何升級呢? 下面就請按我的步驟來將Abp由V1.0升級

ABP入門系列16——通過webapi與系統進行互動

1. 引言 上一節我們講解了如何建立微信公眾號模組,這一節我們就繼續跟進,來講一講公眾號模組如何與系統進行互動。 微信公眾號模組作為一個獨立的web模組部署,要想與現有的【任務清單】進行互動,我們要想明白以下幾個問題: 如何進行互動? ABP模板專案中預設建立了webapi專案,其動態webapi技術允

ABP入門系列14——應用BootstrapTable表格外掛

1. 引言 之前的文章ABP入門系列(7)——分頁實現講解了如何進行分頁展示,但其分頁展示僅適用於前臺web分頁,在後臺管理系統中並不適用。後臺管理系統中的資料展示一般都是使用一些表格外掛來完成的。這一節我們就使用BootstrapTable進行舉例說明。 2. BootstrapTable 基於 B

ABP入門系列6——定義導航選單

完成了增刪改查以及頁面展示,這一節我們來為任務清單新增【導航選單】。 在以往的專案中,大家可能會手動在layout頁面中新增一個a標籤來新增導航選單,這也是一種方式,但是如果要針對不同使用者不同許可權決定是否顯示某個選單,那麼直接在layout頁面中去控制就不方便了。 不過,ABP已經為大家考慮了這一點,集

ABP入門系列19——使用領域事件

1.引言 最近剛學習了下DDD中領域事件的理論知識,總的來說領域事件主要有兩個作用,一是解耦,二是使用領域事件進行事務的拆分,通過引入事件儲存,來實現資料的最終一致性。若想了解DDD中領域事件的概念,可參考DDD理論學習系列(9)-- 領域事件。 Abp中使用事件匯流排來實現領域事件,而關於事件匯流排的

ABP入門系列9——許可權管理

完成了簡單的增刪改查和分頁功能,是不是覺得少了點什麼? 是的,少了許可權管理。既然涉及到了許可權,那我們就細化下任務清單的功能點: 登入的使用者才能檢視任務清單 使用者可以無限建立任務並分配給自己,但只能對自己建立的任務進行查詢、修改 管理員可以建立任務並分配給他人 管理員具有刪除任務的許可權 從以上

ABP入門系列5——展現層實現增刪改查

這一章節將通過完善Controller、View、ViewModel,來實現展現層的增刪改查。最終實現效果如下圖: 一、定義Controller ABP對ASP.NET MVC Controllers進行了整合,通過引入Abp.Web.Mvc名稱空間,建立Controller繼承自AbpControlle

ABP入門系列18—— 使用領域服務

1.引言 自上次更新有一個多月了,發現越往下寫,越不知如何去寫。特別是當遇到DDD中一些概念術語的時候,尤其迷惑。如果只是簡單的去介紹如何去使用ABP,我只需參照官方文件,實現到任務清單Demo中去就可以了,不勞神不費力。但是,這樣就等於一知半解。 知之為知之,不知為不知,是知也。知其然知其所以然,方能舉

ABP入門系列2——領域層建立實體

這一節我們主要和領域層打交道。首先我們要對ABP的體系結構以及從模板建立的解決方案進行一一對應。網上有程式碼生成器去簡化我們這一步的任務,但是不建議初學者去使用。 一、首先來看看ABP體系結構 領域層就是業務層,是一個專案的核心,所有業務規則都應該在領域層實現。 實體(Entity): 實體代表業務領域的

ABP入門系列4——建立應用服務

一、解釋下應用服務層 應用服務用於將領域(業務)邏輯暴露給展現層。展現層通過傳入DTO(資料傳輸物件)引數來呼叫應用服務,而應用服務通過領域物件來執行相應的業務邏輯並且將DTO返回給展現層。因此,展現層和領域層將被完全隔離開來。 以下幾點,在建立應用服務時需要注意: 在ABP中,一個應用服務需要實現IAp

ABP入門系列11——編寫單元測試

1. 前言 In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program

ABP入門系列15——建立微信公眾號模組

1. 引言 現在的網際網路已不在僅僅侷限於網頁應用,IOS、Android、平板、智慧家居等平臺正如火如荼的迅速發展,移動應用的需求也空前旺盛。所有的網際網路公司都不想錯過這一次移動浪潮,佈局移動市場分一份移動紅利。 的確,智慧手機作為我們日常生活已必不可少的一部分,通過手機app能夠獲得更好的體驗,比如

ABP入門系列3——領域層定義倉儲並實現

一、先來介紹下倉儲 倉儲(Repository): 倉儲用來操作資料庫進行資料存取。倉儲介面在領域層定義,而倉儲的實現類應該寫在基礎設施層。 在ABP中,倉儲類要實現IRepository介面,介面定義了常用的增刪改查以及聚合方法,其中包括同步及非同步方法。主要包括以下方法: ABP針對不同的ORM框架對

ABP入門系列1——通過模板建立MAP版本專案

一、從官網建立模板專案 依次按下圖選擇: 輸入驗證碼開始下載 下載提示: 二、啟動專案 使用VS2015開啟專案,還原Nuget包: 設定以Web結尾的專案,設定為啟動專案: 開啟Web.config,修改連線字串。(因為我本地裝的sqlserver是例項是.sqlexpress,所以需要

ABP入門系列13——Redis快取用起來

1. 引言 建立任務時我們需要指定分配給誰,Demo中我們使用一個下拉列表用來顯示當前系統的所有使用者,以供使用者選擇。我們每建立一個任務時都要去資料庫取一次使用者列表,然後繫結到使用者下拉列表顯示。如果就單單對一個demo來說,這樣實現也無可厚非,但是在正式專案中,顯然是不合理的,浪費程式效能,有待優化

ABP入門系列7——分頁實現

完成了任務清單的增刪改查,咱們來講一講必不可少的的分頁功能。 首先很慶幸ABP已經幫我們封裝了分頁實現,實在是貼心啊。 來來來,這一節咱們就來捋一捋如何使用ABP的進行分頁吧。 一、分頁請求DTO定義 資料傳輸物件(Data Transfer Objects)用於應用層和展現層的資料傳輸。 展現層傳入資料

ABP入門系列17——使用ABP整合的郵件系統傳送郵件

ABP中對郵件的封裝主要整合在Abp.Net.Mail和Abp.Net.Mail.Smtp名稱空間下,相應原始碼在此。 #一、Abp整合的郵件模組是如何實現的 分析可以看出主要由以下幾個核心類組成: EmailSettingNames:靜態常量類,主要定義了傳送郵件需要的相關引數:Port、Host、Us