Mybatis系列第11篇:類型處理器,這個(gè)你得會(huì)玩

文章轉(zhuǎn)載自:http://www.itsoku.com/article/256

Mybatis系列目標(biāo):從入門開始開始掌握一個(gè)高級(jí)開發(fā)所需要的Mybatis技能。
這是mybatis系列第11篇,源碼位于文章尾部!

mybatis內(nèi)部參數(shù)設(shè)置和結(jié)果的處理

先來(lái)看一個(gè)案例:

jdbc的方式插入用戶信息,參數(shù)為UserModel:

public class UserModel {
    private Integer id;
    private String name;
    private Integer age;
    //省略了get set方法
}

public static int insert(UserModel userModel) throws SQLException {
    Connection connection = null;
    String sql = "insert into t_user (id,name,age) values (?,?,?)";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    preparedStatement.setInt(1,userModel.getId());
    preparedStatement.setString(2,userModel.getName());
    preparedStatement.setInt(3,userModel.getAge());
    return preparedStatement.executeUpdate();
}

上面我們調(diào)用了preparedStatement的幾個(gè)方法來(lái)設(shè)置參數(shù),如下:

preparedStatement.setInt(1,userModel.getId());
preparedStatement.setString(2,userModel.getName());
preparedStatement.setInt(3,userModel.getAge());

當(dāng)我們使用mybatis插入用戶信息的時(shí)候,mybatis底層也會(huì)調(diào)用PreparedStatement的這些設(shè)置參數(shù)的方法,mybatis底層是如何判斷調(diào)用哪個(gè)方法的呢?

是調(diào)用setInt方法還是setString方法的呢?

再來(lái)看一個(gè)jdbc查詢的案例,查詢出t_user表所有數(shù)據(jù),將其轉(zhuǎn)換為UserModel對(duì)象,核心代碼如下:

public static List<UserModel> getList() throws Exception {
    List<UserModel> result = new ArrayList<>();
    Connection connection = null;
    String sql = "select id,name,age from t_user";
    PreparedStatement preparedStatement = connection.prepareStatement(sql);
    ResultSet rs = preparedStatement.executeQuery();
    while (rs.next()) {
        UserModel userModel = new UserModel();
        userModel.setId(rs.getInt(1));
        userModel.setName(rs.getString(2));
        userModel.setAge(rs.getInt(3));
        result.add(userModel);
    }
    return result;
}

上面有幾行從ResultSet獲取數(shù)據(jù)的方法,如下:

userModel.setId(rs.getInt(1));
userModel.setName(rs.getString(2));
userModel.setAge(rs.getInt(3));

如果使用mybatis實(shí)現(xiàn),mybatis可以將sql結(jié)果自動(dòng)映射到UserModel中的屬性中,mybatis內(nèi)部給UserModel的id設(shè)置值的時(shí)候,mybatis內(nèi)部是如何知道是調(diào)用rs.getInt還是調(diào)用rs.getString來(lái)獲取id列的值的呢?

這些就是mybatis中類型轉(zhuǎn)換器做的事情,類型轉(zhuǎn)換器主要有2個(gè)功能:

  1. 參數(shù)設(shè)置,即設(shè)置參數(shù)的時(shí)候需要調(diào)用PreparedStatement中哪個(gè)set方法去設(shè)置參數(shù),比如:插入用戶信息id字段,id字段是java中的Integer類型的,mybatis內(nèi)部知道需要調(diào)用setInt方法去給id字段設(shè)置參數(shù)。
  2. 將sql查詢結(jié)果轉(zhuǎn)換為對(duì)應(yīng)的java類型,即調(diào)用ResultSet中的哪個(gè)get方法去獲取參數(shù),比如:id在數(shù)據(jù)中是int類型的,讀取的時(shí)候會(huì)調(diào)用ResultSet的getInt方法去讀取,而name字段在db中是varchar類型的,讀取的時(shí)候會(huì)調(diào)用getString方法去讀取,而不是調(diào)用getInt方法去讀取。

mybatis中定義了一個(gè)類型轉(zhuǎn)換器的接口:

public interface TypeHandler<T> {

  void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException;

  /**
   * @param columnName Colunm name, when configuration <code>useColumnLabel</code> is <code>false</code>
   */
  T getResult(ResultSet rs, String columnName) throws SQLException;

  T getResult(ResultSet rs, int columnIndex) throws SQLException;

  T getResult(CallableStatement cs, int columnIndex) throws SQLException;

}

第一個(gè)方法用于通過(guò)PreparedStatement設(shè)置參數(shù)的,即內(nèi)部會(huì)根據(jù)參數(shù)的類型,去調(diào)用PreparedStatement中對(duì)應(yīng)的方法去設(shè)置參數(shù)的值,比如是調(diào)用setInt方法呢還是setString方法,每個(gè)類型轉(zhuǎn)換器中實(shí)現(xiàn)的是不同的。其他3個(gè)方法是從結(jié)果集中讀取數(shù)據(jù)的,內(nèi)部具體是調(diào)用結(jié)果集的getInt方法還是getString方法或者是getObject方法,每個(gè)轉(zhuǎn)換器內(nèi)部實(shí)現(xiàn)也是不一樣的。

mybatis內(nèi)部默認(rèn)實(shí)現(xiàn)了很多類型轉(zhuǎn)換器,基本上夠我們用了,比如IntegerTypeHandler轉(zhuǎn)換器,IntegerTypeHandler主要用來(lái)處理java中的Integer、int類型參數(shù)的,所以會(huì)調(diào)用setInt方法設(shè)置參數(shù);讀取的時(shí)候,對(duì)應(yīng)的jdbc中的類型是JdbcType.INTEGER,所以會(huì)調(diào)用getInt方法讀取數(shù)據(jù)庫(kù)返回的值,讀取的結(jié)果是Integer類型的。我們看一下其源碼:

public class IntegerTypeHandler extends BaseTypeHandler<Integer> {

  @Override
  public void setNonNullParameter(PreparedStatement ps, int i, Integer parameter, JdbcType jdbcType)
      throws SQLException {
    ps.setInt(i, parameter);
  }

  @Override
  public Integer getNullableResult(ResultSet rs, String columnName)
      throws SQLException {
    int result = rs.getInt(columnName);
    return result == 0 && rs.wasNull() ? null : result;
  }

  @Override
  public Integer getNullableResult(ResultSet rs, int columnIndex)
      throws SQLException {
    int result = rs.getInt(columnIndex);
    return result == 0 && rs.wasNull() ? null : result;
  }

  @Override
  public Integer getNullableResult(CallableStatement cs, int columnIndex)
      throws SQLException {
    int result = cs.getInt(columnIndex);
    return result == 0 && cs.wasNull() ? null : result;
  }
}

mybatis內(nèi)部默認(rèn)實(shí)現(xiàn)了很多類型轉(zhuǎn)換器,每種類型轉(zhuǎn)換器能夠處理哪些java類型以及能夠處理的JdbcType的類型,這些都在TypeHandlerRegistry進(jìn)行注冊(cè)的,大家可以去看一下這個(gè)類源碼,IntegerTypeHandler也是在這個(gè)類中進(jìn)行注冊(cè)的,代碼如下:

register(Integer.class, new IntegerTypeHandler());
register(int.class, new IntegerTypeHandler());
register(JdbcType.INTEGER, new IntegerTypeHandler());

所以當(dāng)我們參數(shù)是Integer或者int類型的時(shí)候,mybatis會(huì)調(diào)用IntegerTypeHandler轉(zhuǎn)換器中的setInt方法去設(shè)置參數(shù),上面我們的UserModel的id字段是Integer類型的,所以插入數(shù)據(jù)的時(shí)候會(huì)調(diào)用IntegerTypeHandler處理器中的setInt方法去設(shè)置參數(shù),當(dāng)mybatis將t_user表的數(shù)據(jù)自動(dòng)映射為UserModel類型的時(shí)候,mybatis會(huì)發(fā)現(xiàn)id類型是Integer類型,然后會(huì)找到IntegerTypeHandler中對(duì)應(yīng)的讀取結(jié)果集的方法去讀取數(shù)據(jù),即調(diào)用ResultSet的getInt方法讀取id字段的數(shù)據(jù),然后賦值給UserModel中的id屬性。

自定義類型轉(zhuǎn)換器

我們?cè)谟脩舯硇略鲆粋€(gè)性別字段sex,java中我們通過(guò)一個(gè)枚舉來(lái)表示這個(gè)類型,db腳本如下:

DROP DATABASE IF EXISTS `javacode2018`;
CREATE DATABASE `javacode2018`;

USE `javacode2018`;

DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user(
  id int AUTO_INCREMENT PRIMARY KEY COMMENT '用戶id',
  name VARCHAR(32) NOT NULL DEFAULT '' COMMENT '用戶名',
  age SMALLINT NOT NULL DEFAULT 1 COMMENT '年齡',
  sex SMALLINT DEFAULT 0 COMMENT '性別,0:未知,1:男,2:女'
) COMMENT '用戶表';
INSERT INTO t_user VALUES (1,'路人甲Java',30,1),(2,'林志玲',45,2);

t_user對(duì)應(yīng)的Model如下:

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class UserModel implements Serializable {
    private Integer id;
    private String name;
    private Integer age;
    private SexEnum sex;
}

sex是一個(gè)枚舉類型,枚舉定義如下:

/**
 * 性別
 */
public enum SexEnum {
    UNKNOW(0, "未知"),
    MAN(1, "男"),
    WOMAN(2, "女");

    private Integer value;
    private String name;

    SexEnum(Integer value, String name) {
        this.value = value;
        this.name = name;
    }

    public Integer getValue() {
        return value;
    }

    public String getName() {
        return name;
    }

    public static SexEnum getByValue(Integer value) {
        for (SexEnum item : values()) {
            if (item.getValue().equals(value)) {
                return item;
            }
        }
        return null;
    }
}

我們來(lái)寫一個(gè)查詢?nèi)缦拢?/p>

<select id="getList1" resultType="com.javacode2018.chat05.demo10.model.UserModel">
  SELECT id,name,age,sex FROM t_user
</select>

這個(gè)大家都很熟悉了,查詢t_user表,每行結(jié)果轉(zhuǎn)換為一個(gè)UserModel對(duì)象,最后返回一個(gè)List集合,這個(gè)查詢運(yùn)行會(huì)不會(huì)有什么問(wèn)題?

確實(shí)會(huì)報(bào)錯(cuò),如下:

## Cause: org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'sex' from result set.  Cause: java.lang.IllegalArgumentException: No enum constant com.javacode2018.chat05.demo10.enums.SexEnum.1

    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
    at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
    at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:93)

sex字段在t_user中是數(shù)字類型的,最后通過(guò)mybatis查詢,需要賦值給UserModel中的sex字段,這個(gè)字段是一個(gè)枚舉類型的,mybatis不知道這兩者之間如何進(jìn)行轉(zhuǎn)換,所以報(bào)錯(cuò)了。

此時(shí)需要我們指定一個(gè)轉(zhuǎn)換規(guī)則,來(lái)告知mybatis如何進(jìn)行轉(zhuǎn)換,需要我們用到自定義類型轉(zhuǎn)換器了。

自定義一個(gè)類型轉(zhuǎn)換器SexEnumTypeHandle,用來(lái)處理sex字段和SexEnum枚舉之間的相互轉(zhuǎn)換,代碼如下:

package com.javacode2018.chat05.demo10.typehandle;

import com.javacode2018.chat05.demo10.enums.SexEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

@Slf4j
public class SexEnumTypeHandle extends BaseTypeHandler<SexEnum> {
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, SexEnum parameter, JdbcType jdbcType) throws SQLException {
        ps.setInt(i, parameter.getValue());
        log.info("{}", parameter);
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, String columnName) throws SQLException {
        log.info("{}", columnName);
        Object object = rs.getObject(columnName);
        Integer sex = object != null && object instanceof Integer ? (Integer) object : null;
        return SexEnum.getByValue(sex);
    }

    @Override
    public SexEnum getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        log.info("{}", columnIndex);
        Object object = rs.getObject(columnIndex);
        Integer sex = object != null && object instanceof Integer ? (Integer) object : null;
        return SexEnum.getByValue(sex);
    }

    @Override
    public SexEnum getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        log.info("{}", columnIndex);
        Object object = cs.getObject(columnIndex);
        Integer sex = object != null && object instanceof Integer ? (Integer) object : null;
        return SexEnum.getByValue(sex);
    }
}

自定義類型轉(zhuǎn)換器可以直接繼承BaseTypeHandler,后面有個(gè)泛型,泛型類型為需要處理的java類型,即SexEnum。

類型轉(zhuǎn)換器定義好了,需要將其注冊(cè)到mybatis中,需要在mybatis配置文件中加入:

<typeHandlers>
    <typeHandler handler="com.javacode2018.chat05.demo10.typehandle.SexEnumTypeHandle"/>
</typeHandlers>

再次運(yùn)行一下上面的查詢,對(duì)應(yīng)測(cè)試用例:

com.javacode2018.chat05.demo10.Demo10Test#getModelList

@Test
public void getModelList() throws IOException {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> paramMap = new HashMap<>();
        List<UserModel> userModelList = mapper.getList1(paramMap);
        log.info("{}", userModelList);
    }
}

運(yùn)行結(jié)果:

26:26.144 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==>  Preparing: SELECT id,name,age,sex FROM t_user 
26:26.167 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - ==> Parameters: 
26:26.187 [main] INFO  c.j.c.d.typehandle.SexEnumTypeHandle - sex
26:26.189 [main] INFO  c.j.c.d.typehandle.SexEnumTypeHandle - sex
26:26.189 [main] DEBUG c.j.c.d.mapper.UserMapper.getList1 - <==      Total: 2
26:26.190 [main] INFO  c.j.chat05.demo10.Demo10Test - [UserModel(id=1, name=路人甲Java, age=30, sex=MAN), UserModel(id=2, name=林志玲, age=45, sex=WOMAN)]

這下正常了,看一下輸出中的sex屬性,對(duì)應(yīng)的為枚舉的名稱。

在此案例代碼的基礎(chǔ)上,我們?cè)賮?lái)一個(gè)案例,向用戶表插入用戶信息,參數(shù)為一個(gè)map,每個(gè)字段的值丟在map中,key為字段的名稱,sex我們傳遞SexEnum枚舉類型。

對(duì)應(yīng)的java測(cè)試用例代碼如下:

com.javacode2018.chat05.demo10.Demo10Test#insert1

@Test
public void insert1() throws IOException {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<>();
        Integer id = Integer.valueOf(Calendar.getInstance().getTime().getTime() / 1000 + "");
        map.put("id", id);
        map.put("name", id.toString());
        map.put("age", 30);
        map.put("sex", SexEnum.WOMAN);
        int result = mapper.insert1(map);
        log.info("{}", result);
    }
}

對(duì)應(yīng)mapper xml我們按照下面這種寫法,如:

<insert id="insert1" parameterType="map">
    insert into t_user (id,name,age,sex)
    VALUE (#{id},#{name},#{age},#{sex})
</insert>

這么寫會(huì)不會(huì)有問(wèn)題?我們來(lái)運(yùn)行一下:

32:36.343 [main] DEBUG c.j.c.d.mapper.UserMapper.insert1 - ==>  Preparing: insert into t_user (id,name,age,sex) VALUE (?,?,?,?) 
32:36.378 [main] INFO  c.j.c.d.typehandle.SexEnumTypeHandle - WOMAN
32:36.381 [main] DEBUG c.j.c.d.mapper.UserMapper.insert1 - ==> Parameters: 1578889956(Integer), 1578889956(String), 30(Integer), 2(Integer)
32:36.387 [main] DEBUG c.j.c.d.mapper.UserMapper.insert1 - <==    Updates: 1
32:36.387 [main] INFO  c.j.chat05.demo10.Demo10Test - 1

插入成功了,map中sex對(duì)應(yīng)的是SexEnum.WOMAN,mybatis中判斷map中sex對(duì)應(yīng)的是SexEnum類型的,所以會(huì)找到其對(duì)應(yīng)的類型轉(zhuǎn)換器SexEnumTypeHandle,注意上面日志中的第二行,這個(gè)就是SexEnumTypeHandle轉(zhuǎn)換器中輸出的日志,說(shuō)明設(shè)置sex參數(shù)的時(shí)候執(zhí)行了SexEnumTypeHandle中的代碼。

但是當(dāng)我們不傳遞sex的值的時(shí)候,或者說(shuō)sex傳遞為null的時(shí)候,此時(shí)mybatis是無(wú)法判斷map中sex對(duì)應(yīng)的具體類型的,mybatis內(nèi)部將無(wú)法判斷sex參數(shù)的設(shè)置的時(shí)候,無(wú)法找到具體用哪個(gè)類型轉(zhuǎn)換器給sex設(shè)置參數(shù),這個(gè)在mysql中不會(huì)報(bào)錯(cuò),但是在oracle中會(huì)報(bào)錯(cuò),大家機(jī)器上有oracle的,可以去試試下面代碼運(yùn)行結(jié)果:

@Test
public void insert1() throws IOException {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        Map<String, Object> map = new HashMap<>();
        Integer id = Integer.valueOf(Calendar.getInstance().getTime().getTime() / 1000 + "");
        map.put("id", id);
        map.put("name", id.toString());
        map.put("age", 30);
        map.put("sex", null);
        int result = mapper.insert1(map);
        log.info("{}", result);
    }
}

上面代碼oracle中執(zhí)行會(huì)報(bào)錯(cuò),需要修改對(duì)應(yīng)的mapper xml中的代碼,需要讓mybatis明確知道sex字段需要用哪個(gè)類型轉(zhuǎn)換器進(jìn)行處理,有2種寫法。

第一種,通過(guò)typeHandler屬性明確指定參數(shù)的類型轉(zhuǎn)換器,如下

<insert id="insert1" parameterType="map">
    insert into t_user (id,name,age,sex)
    VALUE (#{id},#{name},#{age},#{sex,typeHandler=com.javacode2018.chat05.demo10.typehandle.SexEnumTypeHandle})
</insert>

第二種,可以指定sex字段的類型,需要通過(guò)javaType屬性來(lái)指定參數(shù)的具體類型,如下:

<insert id="insert1" parameterType="map">
    insert into t_user (id,name,age,sex)
    VALUE (#{id},#{name},#{age},#{sex,javaType=com.javacode2018.chat05.demo10.enums.SexEnum})
</insert>

mybatis通過(guò)java的類型就可以找到對(duì)應(yīng)的類型轉(zhuǎn)換器,所以方式2也是正常的。

再來(lái)總結(jié)一下自定義類型轉(zhuǎn)換器的使用步驟:

  1. 自定義類型轉(zhuǎn)換器,繼承BaseTypeHandler
  2. 將自定義類型轉(zhuǎn)換器注冊(cè)到mybatis中,需要在mybatis配置文件中通過(guò)typeHandler元素進(jìn)行引入
  3. mapper xml中就可以使用了。

案例代碼

鏈接:https://pan.baidu.com/s/1vt-MAX3oJOu9gyxZAhKkbg 
提取碼:i8op
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,402評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評(píng)論 0 287
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,596評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,784評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評(píng)論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,027評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,398評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,743評(píng)論 2 370