Spring boot学习(五)Spring boot整合Mybatis Generator以及PageHelper

前言

在之前的博客中介绍了Spring boot整合Mybatis以及Druid,本篇博客主要介绍如何在Spring boot中整合Mybatis的逆向工程Mybatis Generator以下简称为MBG,以及实际项目中十分方便简单的物理分页插件PageHelper,使用这些插件能极大的减轻我们的开发过程那些简单重复的过程,本篇博客在项目已经整合了Mybatis的基础上进行,没有整合Mybatis的朋友可以参考 Spring boot整合Mybatis

文章首发于个人博客:【http://www.xiongfrblog.cn

整合MBG

为什么使用MBG

使用过Mybatis的朋友应该都知道,在使用之前我们需要根据数据库表的情况在项目中创建出对应的实体类,sql语句接口层,XML文件等,这一系列的操作是非常简单的,但又是必不可少的,耗时耗力还没什么营养,如果数据库的表足够多的时候还要手动创建这些内容,那对程序员来说简直是一种折磨,所以在实际的开发过程中MBG是非常有必要的,下面我们就详细介绍如何在Spring boot项目中配置MBG

在pom.xml中添加MBG插件

<plugins></plugins>标签中添加如下内容:

<!-- Mybatis Generator插件 -->
<plugin>
    <groupId>org.mybatis.generator</groupId>
    <artifactId>mybatis-generator-maven-plugin</artifactId>
    <version>1.3.2</version>
    <configuration>
        <!-- 配置文件的位置 -->
        <configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
        <!-- 允许移动生成的文件 -->
        <verbose>true</verbose>
        <!-- 是否覆盖,true表示会替换生成的Java文件,false则不覆盖 -->
        <overwrite>true</overwrite>
    </configuration>
    <executions>
       <execution>
           <id>Generate MyBatis Artifacts</id>
           <goals>
               <goal>generate</goal>
           </goals>
       </execution>
   </executions>
   <dependencies>
       <dependency>
          <groupId>org.mybatis.generator</groupId>
          <artifactId>mybatis-generator-core</artifactId>
          <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.0</version>
        </dependency>
   </dependencies>
</plugin>

其中configurationFileMBG配置文件的位置可以根据自己的实际情况改写。

注意:如上所示,我们在插件内还添加了mysqlmybatis的依赖项,这两项依赖我们在项目的依赖项里已经添加过了,但是这里还需要再添加一次,我在配置这里的时候如果这里不添加执行插件的时候就会报错。

添加generatorConfig.xml配置文件

这一步是我们生成实体类等的关键,所有的规则都是在这个配置文件里配置的。
首先在src/main/resources目录下创建generator目录,在该目录下创建generatorConfig.xml配置文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>

    <!-- 导入配置文件 -->
    <properties resource="application.properties"/>
    
    <!-- defaultModelType="flat" s设置复合主键时不单独为主键创建实体 -->
    <context id="MySql" defaultModelType="flat" targetRuntime="MyBatis3Simple">
    
        <property name="javaFileEncoding" value="UTF-8"/>
        <!-- 当表名或者字段名为SQL关键字的时候,可以设置该属性为true,MBG会自动给表名或字段名添加分隔符(反单引号) -->
        <property name="autoDelimitKeywords" value="true"/>
        
        <!-- 由于beginningDelimiter和endingDelimiter的默认值为双引号("),在Mysql中不能这么写,所以还要将这两个默认值改为反单引号(`), -->
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/> 
        
        <!-- 生成的POJO实现java.io.Serializable接口 -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin" />

        <!--注释-->
        <commentGenerator>
            <!-- 阻止生成注释 -->
            <property name="suppressAllComments" value="true"/>
            <!-- 注释里不添加日期 -->
            <property name="suppressDate" value="true"/>
        </commentGenerator>
        <!-- 数据库连接,直接通过${}读取application.properties里的配置 -->
        <jdbcConnection
                driverClass="${spring.datasource.driverClassName}"
                connectionURL="${spring.datasource.url}"
                userId="${spring.datasource.username}"
                password="${spring.datasource.password}"/>

        <!-- 生成POJO对象,并将类放到com.web.springbootmybatis.entity包下 -->
        <javaModelGenerator targetPackage="com.web.springboot.entity" targetProject="src/main/java"></javaModelGenerator>
        <!-- 生成mapper xml文件,并放到resources下的mapper文件夹下 -->
        <sqlMapGenerator targetPackage="mapper"  targetProject="src/main/resources"></sqlMapGenerator>

        <!-- 生成mapper xml对应dao接口,放到com.web.springbootmybatis.dao包下-->
        <javaClientGenerator targetPackage="com.web.springboot.dao" targetProject="src/main/java" type="XMLMAPPER"></javaClientGenerator>

        <!-- table标签可以有多个,至少一个,tableName指定表名,可以使用_和%通配符,我这里的配置表明匹配所有的表 -->
        <table tableName="%">
            <!-- 是否只生成POJO对象 -->
            <property name="modelOnly" value="false"/>
            <!-- 插入一条数据时,将id映射到实体类中 -->
            <generatedKey column="id" sqlStatement="Mysql"/>
        </table>
    </context>
</generatorConfiguration>

上面的配置是最常用的配置,注意使用的时候包名,数据库连接等某些配置需要根据自己的实际情况改写,一般使用这个就已经可以了,如果有其他的特别的需求可以参考这篇博客,里边讲解了该配置文件所有标签,属性的意思,解释的非常清楚,想要深入了解的朋友请移步【传送门

执行插件

  1. eclipse中,右键项目-->Run As-->Maven build...-->在Goals中填写命令mybatis-generator:generate,点击Run即可。
  2. 在命令行中运行,需要切换到项目pom.xml文件所在的目录,运行命令mvn mybatis-generator:generate即可。

执行完之后会发现项目中已经创好了相应的类以及接口文件,项目结构图:

在这里插入图片描述

实体类demo:

package com.web.springboot.entity;

import java.io.Serializable;

public class SysUser implements Serializable {
    private Integer id;

    private String usercode;

    private String username;

    private String password;

    private String salt;

    private String locked;

    private static final long serialVersionUID = 1L;

    //省略getter.setter方法
}

sql接口demo:

package com.web.springboot.dao;

import com.web.springboot.entity.SysUser;
import java.util.List;

public interface SysUserMapper {
    int deleteByPrimaryKey(Integer id);

    int insert(SysUser record);

    SysUser selectByPrimaryKey(Integer id);

    List<SysUser> selectAll();

    int updateByPrimaryKey(SysUser record);
}

xml文件demo:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.web.springboot.dao.SysUserMapper" >
  <resultMap id="BaseResultMap" type="com.web.springboot.entity.SysUser" >
    <id column="id" property="id" jdbcType="INTEGER" />
    <result column="usercode" property="usercode" jdbcType="VARCHAR" />
    <result column="username" property="username" jdbcType="VARCHAR" />
    <result column="password" property="password" jdbcType="VARCHAR" />
    <result column="salt" property="salt" jdbcType="VARCHAR" />
    <result column="locked" property="locked" jdbcType="CHAR" />
  </resultMap>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer" >
    delete from sys_user
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.web.springboot.entity.SysUser" >
    <selectKey resultType="java.lang.Integer" keyProperty="id" order="BEFORE" >
      SELECT LAST_INSERT_ID()
    </selectKey>
    insert into sys_user (id, usercode, username, 
      `password`, salt, locked
      )
    values (#{id,jdbcType=INTEGER}, #{usercode,jdbcType=VARCHAR}, #{username,jdbcType=VARCHAR}, 
      #{password,jdbcType=VARCHAR}, #{salt,jdbcType=VARCHAR}, #{locked,jdbcType=CHAR}
      )
  </insert>
  <update id="updateByPrimaryKey" parameterType="com.web.springboot.entity.SysUser" >
    update sys_user
    set usercode = #{usercode,jdbcType=VARCHAR},
      username = #{username,jdbcType=VARCHAR},
      `password` = #{password,jdbcType=VARCHAR},
      salt = #{salt,jdbcType=VARCHAR},
      locked = #{locked,jdbcType=CHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Integer" >
    select id, usercode, username, `password`, salt, locked
    from sys_user
    where id = #{id,jdbcType=INTEGER}
  </select>
  <select id="selectAll" resultMap="BaseResultMap" >
    select id, usercode, username, `password`, salt, locked
    from sys_user
  </select>
</mapper>

我使用过的就这两种,亲测可行,还有其他的方式,具体请参考官方文档【传送门

配置中的一些常见错误及解决方式

  • pom.xml文件中添加完插件之后报错如下:

    Plugin execution not covered by lifecycle configuration:
    org.mybatis.generator:mybatis-generator-maven-plugin:1.3.2:generate
    (execution: Generate MyBatis Artifacts, phase: generate-sources)
    

    解决方式:在<plugins> 标签外再套一个 <pluginManagement> 标签,如下:

    <build>
        <pluginManagement>
            <plugins>
                <plugin> ... </plugin>
                <plugin> ... </plugin>
                ....
            </plugins>
        </pluginManagement>
    </build>
    

    如果还没解决可以参照这里【传送门

  • 执行插件的时候失败并报错如下:

    在这里插入图片描述

    这一类错误出现的最多,解决的办法也不是唯一的,我根据自己的踩坑以及网上的资料提供两个大的方向。

    解决方式:

    1. 插件版本问题,可以网上搜索换一个版本试试。
    2. generatorConfig.xml里边有错误,比如变量名不对,包名不对等,仔细检查往往有惊喜。

整合PageHelper

PageHelper是一款非常简单的分页插件,只需要两行代码即可,不需要我们自己编写sql语句,自动帮我们实现,非常好用,下面开始介绍Spring boot整合PageHelper

添加依赖

首先在pom.xml文件中添加依赖,如下:

<!-- springboot分页插件 -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
    <!-- 特别注意版本问题 -->
    <version>1.2.3</version>
</dependency>

添加这个依赖之后,我们其实不需要再添加mybatis-spring-boot-starter的依赖了,因为pagehelper-spring-boot-starter已经将其包含在其中了。

配置文件中添加配置

aiilication.properties文件中添加如下内容:

#pageHelper配置
pagehelper.helperDialect=mysql
pagehelper.reasonable=true
pagehelper.params=count=countSql
pagehelper.supportMethodsArguments=true

这里简单介绍下几个参数的意思,网上的教程普遍没写,这里介绍下:

  • helperDialect:配置使用哪种数据库语言,不配置的话pageHelper也会自动检测,我这里使用的mysql
  • reasonable:配置分页参数合理化功能,默认是false。启用合理化时,如果pageNum<1会查询第一页,如果pageNum>总页数会查询最后一页; 禁用合理化时,如果pageNum<1或pageNum>总页数会返回空数据。
  • params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值,默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero
  • supportMethodsArguments:支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。

更多参数的介绍请移步【传送门

代码中使用

经过上面的介绍使用MBG已经为我们创建好了实体类,sql接口以及xml文件,现在我们需要创建service层,这里我们利用泛型知识先创建一个service层的基类接口IBaseService.java,之后所有的service接口都继承这个基类接口,这在实际的项目中是很有必要的,减少重复没必要的操作,代码如下:

package com.web.springboot.service;

import java.util.List;

/**
* @author Promise
* @createTime 2019年1月20日 下午8:24:40
* @description service接口层基类,包含基本的   CRUD操作。
*/
public interface IBaseService<T> {
    
    /**
     * 根据主键删除
     * @param id
     * @return
     */
    int deleteByPrimaryKey(Object id);

    /**
     * 新增一条记录
     * @param entity
     * @return
     */
    int insert(T entity);

    /**
     * 根据主键查询
     * @param id
     * @return
     */
    T selectByPrimaryKey(Object id);

    /**
     * 查询全部记录
     * @return
     */
    List<T> selectAll();

    /**
     * 根据主键修改数据
     * @param entity
     * @return
     */
    int updateByPrimaryKey(T entity);
}

该基类接口定义了基本的CRUD操作,我这里写的比较简单,实际中完全可以根据自己的需求完善。

然后创建ISysUserService.java接口,继承该基类接口,并定义两个我们验证pageHelper的方法:

package com.web.springboot.service;

import java.util.List;

import com.github.pagehelper.PageInfo;
import com.web.springboot.entity.SysUser;

/**
* @author Promise
* @createTime 2019年1月20日 下午8:31:09
* @description 
*/
public interface ISysUserService extends IBaseService<SysUser>{

    List<SysUser> findAllByPage(int pageNum, int pageSize);
    
    PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize);
}

  • findAllByPage:实现简单的分页,返回所需对象的list集合,其中参数pageNum代表当前页,pageSize代表每页多少条数据。
  • findAllByPage2:实现简单的分页,返回PageInfo<T>对象,包括所需对象的list集合,还包括数据库总记录数,总页数,当前页,下一页等诸多信息,其中参数pageNum代表当前页,pageSize代表每页多少条数据。

可以根据项目实际需要选择使用哪一种方法。

接口实现类SysUserServiceImpl.java,代码如下:

package com.web.springboot.service.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.web.springboot.dao.SysUserMapper;
import com.web.springboot.entity.SysUser;
import com.web.springboot.service.ISysUserService;

/**
* @author Promise
* @createTime 2019年1月20日 下午8:31:50
* @description 
*/
@Service("sysUserService")
public class SysUserServiceImpl implements ISysUserService{
    
    @Autowired
    private SysUserMapper sysUserMapper;

    @Override
    public int deleteByPrimaryKey(Object id) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public int insert(SysUser entity) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public SysUser selectByPrimaryKey(Object id) {
        // TODO Auto-generated method stub
        return sysUserMapper.selectByPrimaryKey((Integer)id);
    }

    @Override
    public List<SysUser> selectAll() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int updateByPrimaryKey(SysUser entity) {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public List<SysUser> findAllByPage(int pageNum, int pageSize) {
        // TODO Auto-generated method stub
        PageHelper.startPage(pageNum, pageSize);
        List<SysUser> lists = sysUserMapper.selectAll();
        return lists;
    }

    @Override
    public PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize) {
        // TODO Auto-generated method stub
        PageHelper.startPage(pageNum, pageSize);
        List<SysUser> lists = sysUserMapper.selectAll();
        PageInfo<SysUser> pageInfo = new PageInfo<SysUser>(lists);
        return pageInfo;
    }
}

可以看到该类中实现了我们在基类接口IBaseService.java以及ISysUSerService.java里边定义的所有方法,这里我们先重点关注findAllByPage(int pageNum, int pageSize)方法中的

PageHelper.startPage(pageNum, pageSize);
List<SysUser> lists = sysUserMapper.selectAll();

这段代码,第一句使用了我们的分页插件,就这一句即可,需要注意的是查询语句必须紧跟这一句,且只能使用一次,意思就是如果还有一个分页查询需要再定义一次PageHelper.startPage(pageNum, pageSize)

再来说findAllByPage2(int pageNum, int pageSize)方法,只比上边的方法多一句话,且返回结果不一样

PageInfo<SysUser> pageInfo = new PageInfo<SysUser>(lists);

当然,PageHelper还有其它的多种使用方式,上面的方式要想保证正确性必须要查询代码紧跟分页代码才行,需要程序员去控制,这就增加了出现错误的几率,所以这里再介绍一种更为安全的方式--ISelect 接口方式:

findAllByPage(int pageNum, int pageSize)改版:

@Override
public List<SysUser> findAllByPage(int pageNum, int pageSize) {
    //这种写法需要jdk8 lambda用法
    Page<SysUser> page = PageHelper.startPage(pageNum, pageSize).doSelectPage(()-> sysUserMapper.selectAll());
    //如果是低版本的jdk,则使用如下写法(两种写法根据自己jdk版本二选一)
    Page<SysUser> page = PageHelper.startPage(pageNum, pageSize).doSelectPage(new ISelect() {
        @Override
        public void doSelect() {
            sysUserMapper.selectAll();
        }
    });
    return page;
}

看到这里有的朋友或许会发现我们返回的是一个Page<SysUser>对象,而方法定义的是一个List<SysUser>对象,这里我直接贴出PageHelper中该方法定义的源码大家就一目了然了:

public class Page<E> extends ArrayList<E> implements Closeable {
    //为了不占过多的篇幅,这里只贴出方法定义的源码,想要了解具体内容请自行查看源码。
    //可以看到该方法继承了ArrayList<T>这也是我们可以直接返回Page<SysUser>的原因。
}

findAllByPage2(int pageNum, int pageSize)改版:

@Override
public PageInfo<SysUser> findAllByPage2(int pageNum, int pageSize) {
    //这种写法需要jdk8 lambda用法
    PageInfo<SysUser> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(()-> sysUserMapper.selectAll());
    //如果是低版本的jdk,则使用如下写法(两种写法根据自己jdk版本二选一)
    PageInfo<SysUser> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(new ISelect() {
        @Override
        public void doSelect() {
            sysUserMapper.selectAll();
        }
    });
    return pageInfo;
}

这里就给出这两种使用PageHelper的方法了,想要了解更多请移步【传送门

接下来创建测试控制器TestController.java,如下:

package com.web.springboot.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.github.pagehelper.PageInfo;
import com.web.springboot.entity.SysUser;
import com.web.springboot.service.ISysUserService;

/**
* @author Promise
* @createTime 2019年1月20日 下午8:21:02
* @description 
*/
@RestController
public class TestController {
    
    @Autowired
    private ISysUserService sysUserService;

    @RequestMapping("/users/{pageNum}/{pageSize}")
    public Object getAllUser(@PathVariable int pageNum, @PathVariable int pageSize) {
        List<SysUser> lists=sysUserService.findAllByPage(pageNum, pageSize);
        return lists;
    }
    
    @RequestMapping("/users2/{pageNum}/{pageSize}")
    public Object getAllUser2(@PathVariable int pageNum, @PathVariable int pageSize) {
        PageInfo<SysUser> pageInfo=sysUserService.findAllByPage2(pageNum, pageSize);
        return pageInfo;
    }
}

好了,代码就编写完成了!

验证分页

在这之前,我们需要在数据中准备一些数据,这里先贴上我的数据库数据情况,实际以自身的数据库数据为准:

在这里插入图片描述

启动项目,浏览器访问localhost:8080/users/1/2,表示访问第一页,每页两条数据,结果如下:

在这里插入图片描述

对比数据库,数据返回正确,接下来访问localhost:8080/user2/1/2,结果如下:

在这里插入图片描述

发现json数据没有格式,不利于我们查看,可以使用在线json格式转化工具格式化内容如下:

{
    "pageNum": 1,
    "pageSize": 2,
    "size": 2,
    "startRow": 1,
    "endRow": 2,
    "total": 6,
    "pages": 3,
    "list": [{
        "id": 1,
        "usercode": "Promise",
        "username": "eran",
        "password": "123456",
        "salt": null,
        "locked": "0"
    }, {
        "id": 2,
        "usercode": "Promise2",
        "username": "eran",
        "password": "123456",
        "salt": null,
        "locked": "0"
    }],
    "prePage": 0,
    "nextPage": 2,
    "isFirstPage": true,
    "isLastPage": false,
    "hasPreviousPage": false,
    "hasNextPage": true,
    "navigatePages": 8,
    "navigatepageNums": [1, 2, 3],
    "navigateFirstPage": 1,
    "navigateLastPage": 3,
    "lastPage": 3,
    "firstPage": 1
}

可以发现返回了很多有用的内容,这里就不一一介绍了,字段都浅显易懂,实际开发中我们可以根据需要选择使用哪种方式。

结语

关于Spring boot整合MBG以及pageHelper的内容就到这里了,下篇博客见。bye~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容