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

ABP入門系列目錄——學習Abp框架之實操演練
講完了分頁功能,這一節咱們先不急着實現新的功能。來簡要介紹下Abp中Json的用法。爲何要在這一節講呢?固然是作鋪墊啊,後面的系列文章會常常和Json這個東西打交道。html

1、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"} ] }web

2、Asp.net Mvc中的JsonResult

Asp.net mvc中默認提供了JsonResult來處理須要返回Json格式數據的狀況。
通常咱們能夠這樣使用: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結果,有如下幾點不足:mvc

  • 返回的字段大小寫與代碼中一致。這就要求咱們在前端中也要與代碼中用一致的大小寫進行取值(item.Titleitem.Genreitem.ReleaseDate)。
  • 不包含成功失敗信息:若是咱們要判斷請求是否成功,咱們要手動經過獲取json數據包的length獲取。
  • 返回的日期未格式化,在前端還需自行格式化輸出。

3、Abp中對Json的封裝

因此Abp封裝了AbpJsonResult繼承於JsonResult,其中主要添加了兩個屬性:框架

  • CamelCase:大小駝峯(默認爲true,即小駝峯格式)
  • Indented :是否縮進(默認爲false,即未格式化)

並在AbpController中重載了ControllerJson()方法,強制全部返回的Json格式數據爲AbpJsonResult類型,並提供了AbpJson()的虛方法。asp.net

/// <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結果格式化後:ide

{
  "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特性進行相應的過濾。

4、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。
相關文章
相關標籤/搜索