除了FastJson,你還有選擇: Gson簡易指南

前言

這個周末被幾個技術(shù)博主的同一篇公眾號文章 fastjson又被發(fā)現(xiàn)漏洞,這次危害可導致服務(wù)癱瘓! 刷屏,離之前漏洞事件沒多久播急,fastjson 又出現(xiàn)嚴重 Bug。目前項目中不少使用了 fastjson 做對象與JSON數(shù)據(jù)的轉(zhuǎn)換售睹,又需要更新版本重新部署,可以說是費時費力可训。與此同時昌妹,也帶給我新的思考,面對大量功能強大的開源庫握截,我們不能盲目地引入到項目之中飞崖,眾多開源框架中某個不穩(wěn)定因素就足以讓一個項目遭受滅頂之災。趁著周末谨胞,在家學習下同樣具備JSON與對象轉(zhuǎn)換功能的優(yōu)秀開源框架 Gson固歪,并且打算將今后項目使用 fastjson 的地方逐漸換成使用 Gson,記錄下學習總結(jié)的內(nèi)容胯努,希望對小伙伴也有所幫助牢裳。

本文所涉及所有代碼片段均在下面?zhèn)}庫中,感興趣的小伙伴歡迎參考學習:

https://github.com/wrcj12138aaa/gson-actions

版本支持:

  • JDK 8
  • Gson 2.8.5
  • JUnit 5.5.1
  • Lomok 1.18.8

Gson 簡介

在正式介紹 Gson 之前叶沛,我們可以先從官方的wiki看下 Gson 的描述蒲讯,了解它是什么?

Gson is a Java library that can be used to convert Java Objects into their JSON representation. It can also be used to convert a JSON string to an equivalent Java object灰署。

從描述可以看出判帮,Gson 是用于將 Java 對象與 JSON格式字符串數(shù)據(jù)相互轉(zhuǎn)換的 Java 庫。它起初在Google 內(nèi)部廣泛使用在 Android 平臺 和 Java 服務(wù)端上溉箕。2008 年開源之后晦墙,成為了谷歌又一個被廣泛使用的開源框架,截止目前(2019.09.08) 在GitHub 上已有1W6 多星肴茄,相同作用的類庫還有 Spring Framework 中集成的 Jackson晌畅,以及阿里開源的 fastjson等。

在特性方面独郎,Gson 提供簡易的API fromJson/toJson 來實現(xiàn) Java 與 JSON 之間的轉(zhuǎn)換踩麦,并且能生成緊湊枚赡,可讀的 JSON 字符串輸出,還支持復雜對象轉(zhuǎn)換和豐富的自定義表示谓谦,足以滿足在日常開發(fā)中我們絕大部分的 JSON 數(shù)據(jù)處理需求贫橙。

我們通常將對象與JSON字符串間的轉(zhuǎn)換稱之為序列化和反序列化(Serialization/Deserialization)。將 對象轉(zhuǎn)化成 JSON字符串的過程稱為序列化反粥,將JSON 字符串轉(zhuǎn)化成對象的過程稱為反序列化卢肃。

Gson 基本使用

使用 Gson 框架進行序列化與反序列操作,都離不開 com.google.gson.Gson 對象才顿,它也是 Gson 框架的關(guān)鍵對象莫湘,提供的公共 API 具備了多種序列化和反序列方式。

Gson 對象的創(chuàng)建主要有兩種方式:

  • 使用 new 關(guān)鍵字直接創(chuàng)建:Gson gson = new Gson()
  • 由 GsonBuilder 對象構(gòu)建:Gson gson = new GsonBuilder().create()

通常情況下郑气,上面兩種方式創(chuàng)建的 Gson 對象在進行序列化與反序列操作時行為都是一樣的幅垮,但是第二種方式構(gòu)建 Gson 對象時,允許進行額外的行為定制尾组,比如格式化 JSON 字符串的輸出內(nèi)容忙芒,是否序列化 null 值等等。

Java 序列化

簡單對象的序列化

我們可以通過下面的例子來看下通過上述兩種方式序列化 Java 對象的不同效果:

public class ResultTest {
    @Test
    void test_serialization() {
        Gson gson = new Gson();
        Result result = new Result(200, "成功", null);
        String json = gson.toJson(result);
        System.out.println("json is " + json);
      
        Gson buildedGson = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
        String buildedJson = buildedGson.toJson(result);
        System.out.println("buildedJson is " + buildedJson);
    }

    class Result {
        private int code;
        private String message;
        private Object data;

        public Result(int code, String message, Object data) {
            this.code = code;
            this.message = message;
            this.data = data;
        }
    }
}

運行該測試用例讳侨,在控制臺可以看到如下日志輸出:

從結(jié)果可以看出呵萨,默認的 Gson 對象行為序列化對象時會將 null 值的字段忽略,而 com.google.gson.GsonBuilder#serializeNulls 方法將允許 Gson 對象序列化 null 字段跨跨;并且正常序列化后的 JSON 字符串是緊湊格式潮峦,節(jié)省字符串內(nèi)存,使用 com.google.gson.GsonBuilder#setPrettyPrinting 方法之后最終輸出的 JSON 字符串是更易讀的格式勇婴。當然除了這兩個方法忱嘹,GsonBuilder 還提供了許多定制序列化和反序列化行為的API,我們將后面的內(nèi)容進一步講解咆耿。

JosnObject 生成 JSON

除了上述將自定義類的對象轉(zhuǎn)換成 JSON 的方式之外德谅,還可以使用 Gson 框架提供的 JsonObject 構(gòu)建普通對象,然后使用 toJson 方法生成 JSON 字符串萨螺,在原測試類中補充下方測試類窄做,并運行查看效果如下

@Test
void test_jsonObject_serialization() {
  Gson gson = new Gson();
  JsonObject jsonObject = new JsonObject();
  jsonObject.addProperty("code", 400);
  jsonObject.addProperty("message", "參數(shù)錯誤");
  String toJson = gson.toJson(jsonObject);
  String exceptedJson = "{\"code\":400,\"message\":\"參數(shù)錯誤\"}";
  Assertions.assertEquals(exceptedJson, toJson); //true
}

JsonObject 使用 addProperty(property,value) 方法只能用來添加 String,Number慰技,Boolean椭盏,Character這四類數(shù)據(jù), 因為內(nèi)部是調(diào)用 com.google.gson.JsonObject#add, 將 value 封裝成了 JsonPrimitive 對象吻商,然后保存到了內(nèi)部自定義的 LinkedTreeMap 集合變量 members 中掏颊;如果需要在 JsonObject 對象上添加其他對象時,就需要直接使用 add(String property, JsonElement value) 方法添加一個 JsonElement 對象。這里的 JsonElement 是一個抽象類乌叶,JsonObject 和 JsonPrimitive 都繼承了JsonElement盆偿,所以我們最終通過另外的 JsonObject 對象來作為原 JsonObject 上的屬性對象:

Gson gson = new Gson();
JsonObject jsonObject = new JsonObject();
//...
JsonObject nestJsonObject = new JsonObject();
nestJsonObject.addProperty("username", "one");
nestJsonObject.addProperty("score", 99);
jsonObject.add("data", nestJsonObject);
String toJson2 = gson.toJson(jsonObject);
System.out.println(toJson2);
// {"code":400,"message":"參數(shù)錯誤","data":{"username":"one","score":99}}

JSON 反序列化

簡單對象的反序列化

現(xiàn)在我們再來看下 JSON 反序列化成 Java 對象用法,這里主要使用方法是 com.google.gson.Gson#fromJson准浴,它最基礎(chǔ)的用法就是 fromJson(String json, Class<T> classOfT)事扭,嘗試將 JSON 字符串轉(zhuǎn)為指定 Class 的對象,如果轉(zhuǎn)換失敗乐横,就會拋出 JsonSyntaxException 異常求橄。我們可以在原來代碼上新增一個測試用例,運行看下效果:

@Test
void test_deserialization() {
    String json = "{\"code\":400,\"message\":\"參數(shù)錯誤\"}";
    Result result = new Gson().fromJson(json, Result.class);
    Assertions.assertEquals(400, result.code); // true
    Assertions.assertEquals("參數(shù)錯誤", result.message); // true
}

反序列化 Map

除了將JSON 字符串序列化為自定義的Java 對象之外葡公,我們還可以轉(zhuǎn)為 Map 集合罐农,Gson 提供了對 Map 集合的轉(zhuǎn)換,使用起來也十分簡單:

@Test
void test_map() {
    String jsonString = "{'employee.name':'one','employee.salary':10}";
    Gson gson = new Gson();
    Map map = gson.fromJson(jsonString, Map.class);
    assertEquals(2, map.size());
        assertEquals("one", map.get("employee.name"));
    assertEquals(Double.class, map.get("employee.name").getClass());
}

需要注意的是轉(zhuǎn)換后的 Map 對象真實類型并不是我們經(jīng)常用的 HashMap催什,而是 Gson 自定義集合LinkedTreeMap 涵亏,它實現(xiàn)Map 接口來存儲鍵值對,在新增和刪除上實現(xiàn)上進行了優(yōu)化蒲凶,并且將存儲鍵值對的順序作為遍歷順序溯乒,也就是先存入的先被遍歷到。除此之外豹爹,JSON 字符串里的數(shù)值型數(shù)據(jù)都會轉(zhuǎn)轉(zhuǎn)換為 Double 類型矛纹,而 true/false 數(shù)據(jù)被會被轉(zhuǎn)換成 Boolean 類型臂聋,具體判斷依據(jù)可以參考 com.google.gson.internal.bind.ObjectTypeAdapter#read 方法的實現(xiàn)。

JSON 與 Array或南,List 轉(zhuǎn)換

JSON 轉(zhuǎn)換 Array

當我們正對 JSON 數(shù)據(jù)進行數(shù)組轉(zhuǎn)換時孩等,類似普通對象轉(zhuǎn)換的方式即可, toJson 方法直接使用轉(zhuǎn)為 JSON 數(shù)據(jù)采够,fromJson 指定數(shù)組類型轉(zhuǎn)換為對應類型的數(shù)組肄方。

@Test
void test_array() {
  Gson gson = new Gson();
  int[] ints = {1, 2, 3, 4, 5};
  String[] strings = {"abc", "def", "ghi"};
  String s = gson.toJson(ints);// [1,2,3,4,5]
  assertEquals("[1,2,3,4,5]", s); // true

  String s1 = gson.toJson(strings);// ["abc", "def", "ghi"]
  assertEquals("[\"abc\",\"def\",\"ghi\"]", s1);
  String[] strings1 = gson.fromJson(s1, String[].class);
  assertEquals(strings.length, strings1.length); // true
  assertEquals(strings[0], strings1[0]); // true

  int[] ints2 = gson.fromJson("[1,2,3,4,5]", int[].class);
  assertEquals(1, ints2[0]); // true
  assertEquals(5, ints2[4]); // true
}

JSON 轉(zhuǎn)換 List

要將 List 數(shù)據(jù)轉(zhuǎn)換為 JSON數(shù)據(jù),使用 Gson 的方式與處理 Array 數(shù)據(jù)一樣蹬癌;這里主要講的是將JSON 數(shù)據(jù)轉(zhuǎn)為 List 對象的操作略有不同权她,要將一個 JSON 數(shù)組數(shù)據(jù)轉(zhuǎn)換為一個自定義類的List 時,我們按照原來的寫法如下:

@Test
public void givenJsonString_whenIncorrectDeserializing() {
    Gson gson = new Gson();
    String inputString = "[{\"id\":1,\"name\":\"one\"},{\"id\":2,\"name\":\"two\"}]";
    List<Person> outputList = gson.fromJson(inputString, List.class);
        outputList.get(0).getId();
}

但是不幸的是逝薪,運行這段代碼后會拋出 ClassCastException 異常隅要,具體描述如下:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.one.learn.Person
...

從上述描述中我們可以知道執(zhí)行 fromJson 之后,反序列化后得到的 List 元素類型為 LinkedTreeMap董济,而不是 Person步清,所以以 Person 對象方式訪問 id 屬性時就會拋出 ClassCastException 異常。那又該如何處理呢, 我們需要調(diào)用 Gson 的 另外一個 fromJson 方法:fromJson(String json, Type typeOfT) ,先看下使用方式

@Test
public void givenJsonString_whenCorrectDeserializing_() {
  Gson gson = new Gson();
  String inputString = "[{\"id\":1,\"name\":\"one\"},{\"id\":2,\"name\":\"two\"}]";
  Type type = new TypeToken<List<Person>>(){}.getType();
  List<Person> outputList = gson.fromJson(inputString, type);
  int id = outputList.get(0).getId();
  assertEquals(1, id); // true
  assertEquals("one", outputList.get(0).getName()); // true
}

這個方法中的 Type 對象通過 TypeToken 對象的 getType 方法獲取到廓啊,就是 TypeToken 對象所關(guān)聯(lián)的泛型類型欢搜。而這里 TypeToken 是 Gson 為了支持泛型而引入的類,來解決 Java 無法提供泛型類型表示的問題谴轮,由于 TypeToken 的構(gòu)造方法是protected修飾的炒瘟,無法直接構(gòu)造,使用就需要寫成new TypeToken<List<String>>() {}.getType() 形式书聚。

Gson 進階用法

接觸了 Gson 基本的使用之后唧领,我們接著進一步學習 Gson 的其他用法。

泛型對象的反序列化

上節(jié)內(nèi)容簡單接觸了 Gson 對泛型的支持雌续,接下來用代碼來展示下它的強大之處斩个,首先我們將上文的 Result 類調(diào)整下接受泛型參數(shù):

class Result<T> {
  private int code;
  private String message;
  private T data;

  public Result(int code, String message, T data) {
    this.code = code;
    this.message = message;
    this.data = data;
  }
}

然后對一個有內(nèi)嵌對象的 JSON字符串進行解析成 Result<User> 對象,示例代碼如下:

@Test
void test_genric_object() {
  String json = "{\"code\":200,\"message\":\"操作成功\",\"data\":{\"username\": \"one\",\"avater\": \"image.jpg\"" +
    "}}";
  Type type = new TypeToken<Result<User>>(){}.getType();
  Result<User> result = new Gson().fromJson(json, type);
  Assertions.assertEquals(200, result.code);
  Assertions.assertEquals("one", result.data.getUsername());
  Assertions.assertEquals("image.jpg", result.data.getAvater());
}

class User {
  private String username;
  private String avater;

  public String getUsername() {
    return username;
  }

  public String getAvater() {
    return avater;
  }
}

利用 TypeToken 對象獲取具體泛型類型 Result<User> , 然后在 fromJson 方法中傳入就會根據(jù)對應類型的執(zhí)行反序列化操作驯杜。

自定義序列化

如果我們要對Java 對象的某些字段進行特殊處理受啥,比如隱藏某些字段的序列化,對字段的數(shù)據(jù)格式化處理等鸽心,我們可以通過實現(xiàn) JsonSerializer 接口滚局,對序列化邏輯進行自定義。例如顽频,我們需要對 Date 類型屬性進行特定格式的處理藤肢,可以聲明 DateSerializer 類實現(xiàn)如下:

class DateSerializer implements JsonSerializer<Date> {
    SimpleDateFormat dateTime = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(dateTime.format(src));
    }
}

然后在構(gòu)建 Gson 對象前,利用 GsonBuilder 將 DateSerializer 實例進行注冊糯景,使用方式如下:

Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateSerializer()).create();

這樣一來嘁圈,一旦遇到要序列化 Date 類型的字段時,都會通過自定義的 serialize 方法將日期以 yyyy-MM-dd 格式進行輸出蟀淮,如下方的示例代碼:

@Test
void test_dateSerializer() {
  MyObject myObject = new MyObject(new Date(), "one");
  Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, new DateSerializer()).create();
  String json = gson.toJson(myObject);
  String exceptedJson = "{\"date\":\"2019-09-08\",\"name\":\"one\"}";
  Assertions.assertEquals(exceptedJson, json); // true
}

class MyObject {
    private Date date;
    private String name;

    public MyObject(Date date, String name) {
        this.date = date;
        this.name = name;
    }

    public MyObject() {
    }
}

自定義反序列化

與自定義序列化實現(xiàn)方式類似最住,想要自定義反序列化邏輯,就需要同樣要實現(xiàn)一個叫 JsonDeserializer 的接口怠惶,進行自定義反序列化邏輯的實現(xiàn)涨缚。比如現(xiàn)在有個 JSON 字符串內(nèi)容為 {"CODE": 400, "MESSAGE": "參數(shù)錯誤"},需要被反序列化為前文提到的 Result 對象策治,由于字段名不一樣脓魏,為了實現(xiàn)對應的轉(zhuǎn)換,就需要自定義 ResultDeserializer 類览妖,具體實現(xiàn)如下:

class ResultDeserializer implements JsonDeserializer<Result> {
    @Override
    public Result deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject object = json.getAsJsonObject();
        Result<Object> result = new Result<>(object.getAsJsonPrimitive("CODE").getAsInt(),object.getAsJsonPrimitive("MESSAGE").getAsString(), null);
        return result;
    }
}

接下來就是利用 GsonBuilder 注冊 ResultDeserializer 實例轧拄,生成對應的 Gson 對象,并進行反序列化操作:

@Test
void test_resultDeserializer() {
    //language=JSON
        String json = "{\"CODE\": 400,\"MESSAGE\": \"參數(shù)錯誤\"}";
    Gson gson = new GsonBuilder().registerTypeAdapter(Result.class, new ResultDeserializer())
            .create();
    Result result = gson.fromJson(json, Result.class);
    Assertions.assertEquals(400, result.code); // true
    Assertions.assertEquals("參數(shù)錯誤", result.message); // true
}

Gson 常用注解

Gson 除了提供一些 API 供開發(fā)者使用之外讽膏,還有一些具有特性的注解可以使用檩电,接下來就介紹在 Gson 中最常用的注解。

@Expose

這個注解只能用在字段上,作用就是注明對應的字段是否將在序列化或者反序列化時暴露出來俐末,有兩個屬性 serializedeserialize 料按,默認都為 true。當給一個字段加上 注解@Expose(serialize = true, deserialize = false)卓箫,則表示了該字段盡在序列化時可見载矿,在反序列化時會忽略賦值。需要額外注意的一點是烹卒,@Expose 注解只有在用 GsonBuilder 方式構(gòu)建 Gson 時有限闷盔,并且構(gòu)建前必須調(diào)用 excludeFieldsWithoutExposeAnnotation 方法,下面是具體的使用示例:


@Test
void test_expose() {
    MySubClass subclass = new MySubClass(42L, "the answer", "Verbose field not to serialize");
    MyClass source = new MyClass(1L, "foo", "bar", subclass);
    Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
    String s = gson.toJson(source);
    System.out.println(s);
        // {"id":1,"name":"foo","subclass":{"id":42,"description":"the answer","otherVerboseInfo":"Verbose field not to serialize"}}
}

@Data
@AllArgsConstructor
class MyClass {
    private long id;
    @Expose(serialize = false, deserialize = true)
    private String name;
    private transient String other;
    @Expose
    private MySubClass subclass;
}

@Data
@AllArgsConstructor
class MySubClass {
    @Expose
    private long id;
    @Expose
    private String description;
    @Expose
    private String otherVerboseInfo;
}

在 Gson 中 transient 關(guān)鍵字修飾的字段默認不會被序列化和反序列化旅急,這個行為是與 Java 原生的序列化和反序列化操作一致的逢勾。

@Since

該注解用于標記對應字段或者類型的版本,讓 Gson 可以指定版本號進行序列化和反序列化操作藐吮。當Web服務(wù)上的 JSON 數(shù)據(jù)對應的類存在多個版本的字段時溺拱,這個注解就十分有用。

同樣地谣辞,該注解只針對使用 GsonBuilder 方式構(gòu)建的 Gson 對象迫摔,并且使用 setVersion 方法指明版本號時有效,只解析對象中對應版本的字段泥从,下面為具體示例:

public class VersioningSupportTest {
    @Test
    void test() {
        VersionedClass versionedObject = new VersionedClass();
        Gson gson = new GsonBuilder().setVersion(1.0).create();
        String jsonOutput = gson.toJson(versionedObject);
        System.out.println(jsonOutput); // {"newField":"new","field":"old"}
    }
}

class VersionedClass {
    @Since(1.1)
    private final String newerField;
    @Since(1.0)
    private final String newField;
    private final String field;

    public VersionedClass() {
        this.newerField = "newer";
        this.newField = "new";
        this.field = "old";
    }
}

@SerializedName

這個注解使用起來比較簡單句占,也很有用。@SerializedName 指定了成員字段被序列化和反序列化時所采用的名稱下面是具體使用方式:

public class JSONFieldNamingSupportTest {
    private class SomeObject {
        @SerializedName("custom_naming")
        private final String someField;
        private final String someOtherField;

        public SomeObject(String a, String b) {
            this.someField = a;
            this.someOtherField = b;
        }
    }

    @Test
    void test() {
        SomeObject someObject = new SomeObject("first", "second");
        String jsonRepresentation = gson.toJson(someObject);
        System.out.println(jsonRepresentation);
        // {"custom_naming":"first","someOtherField":"second"}
        SomeObject someObject1 = gson.fromJson(jsonRepresentation, SomeObject.class);
        System.out.println(someObject1);
        // SomeObject{someField='first', someOtherField='second'}
    }
}

@JsonAdapter

不同于上面的注解躯嫉,@JsonAdapter 只作用于類上辖众,主要作用就是代替 GsonBuilder.registerTypeAdapter 方法的執(zhí)行,直接通過 @JsonAdapter(aClass.class) 方式指定 JsonDeserializer 對象或者 JsonSerializer 對象和敬,可以起到相同的想過,并且優(yōu)先級比GsonBuilder.registerTypeAdapter的優(yōu)先級更高戏阅,由于只是將 registerTypeAdapter方法執(zhí)行簡化成了注解方法昼弟,這里就不再演示,直接在前文自定義反序列化一節(jié)的 Result 類上使用就可以看到效果奕筐。

結(jié)語

本文主要學習總結(jié)了 Gson 框架的序列化和反序列操作使用方式舱痘,以及介紹了 Gson 多種特性用法,希望對處理 JSON 數(shù)據(jù)感到頭疼的小伙伴有所幫助离赫。

推薦閱讀

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渊胸,隨后出現(xiàn)的幾起案子旬盯,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胖翰,死亡現(xiàn)場離奇詭異接剩,居然都是意外死亡,警方通過查閱死者的電腦和手機萨咳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門懊缺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人培他,你說我怎么就攤上這事鹃两。” “怎么了舀凛?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵俊扳,是天一觀的道長。 經(jīng)常有香客問我腾降,道長拣度,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任螃壤,我火速辦了婚禮抗果,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奸晴。我一直安慰自己冤馏,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布寄啼。 她就那樣靜靜地躺著逮光,像睡著了一般。 火紅的嫁衣襯著肌膚如雪墩划。 梳的紋絲不亂的頭發(fā)上涕刚,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音乙帮,去河邊找鬼杜漠。 笑死,一個胖子當著我的面吹牛察净,可吹牛的內(nèi)容都是我干的驾茴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼氢卡,長吁一口氣:“原來是場噩夢啊……” “哼锈至!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起译秦,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤峡捡,失蹤者是張志新(化名)和其女友劉穎击碗,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棋返,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡延都,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了睛竣。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晰房。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖射沟,靈堂內(nèi)的尸體忽然破棺而出殊者,到底是詐尸還是另有隱情,我是刑警寧澤验夯,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布猖吴,位于F島的核電站,受9級特大地震影響挥转,放射性物質(zhì)發(fā)生泄漏海蔽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一绑谣、第九天 我趴在偏房一處隱蔽的房頂上張望党窜。 院中可真熱鬧,春花似錦借宵、人聲如沸幌衣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豁护。三九已至,卻和暖如春欲间,著一層夾襖步出監(jiān)牢的瞬間楚里,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工猎贴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腻豌,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓嘱能,卻偏偏與公主長得像,于是被迫代替她去往敵國和親虱疏。 傳聞我的和親對象是個殘疾皇子惹骂,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容