2-Mybatis进阶

1.Mybatis 接口代理方式实现Dao层

2.Mybatis 映射配置文件-动态SQL

3.Mybatis 核心配置文件-分页插件

4.Mybatis 多表操作

1.Mybatis 接口代理方式实现Dao层

  • 传统方式实现Dao层,我们即要写接口,还要写实现类,而MyBatis框架可以帮助我们省略编写Dao层接口实现类的步骤,程序员只需要编写接口,由MyBatis框架根据接口定义的来创建该接口的动态代理对象
  • 实现规则
    1.映射配置文件中的名称空间必须和Dao层接口的全类名相同
    2.映射配置文件中的增删改查标签的id属性必须和Dao层接口的方法名相同
    3.映射配置文件中的增删改查标签的 parameterType属性必须和Dao层接口方法的参数相同
    4.映射配置文件中的增删改查标签的 resultType属性必须和Dao层接口方法的返回值相同
  • 接口代理方式-(代码实现)
    1.删除mapper层接口的实现类
    2.修改映射配置文件,其他配置不变
<mapper namespace="com.itheima.mapper.StudentMapper">

3.修改service层接口的实现类,采用接口代理方式实现功能

package com.itheima.service.Impl;

import com.itheima.bean.Student;
import com.itheima.mapper.StudentMapper;
import com.itheima.service.StudentService;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import java.io.InputStream;
import java.util.List;

/*
    业务层实现类
 */
public class StudentServiceImpl implements StudentService {

    @Override
    public List<Student> selectAll() {
        List<Student> list = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //获取StudentMapper接口的实现类对象
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            //通过实现类对象调用方法,接受结果
            list = mapper.selectAll();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return list;
    }

    @Override
    public Student selectById(Integer id) {
        SqlSession sqlSession = null;
        InputStream is = null;
        Student student = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //获取StudentMapper接口的实现类对象
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            //通过实现类对象调用方法,接受结果
            student = mapper.selectById(id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return student;
    }

    @Override
    public Integer insert(Student stu) {

        SqlSession sqlSession = null;
        InputStream is = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //获取StudentMapper接口的实现类对象
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            //通过实现类对象调用方法,接受结果
            result = mapper.insert(stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }

    @Override
    public Integer update(Student stu) {
        SqlSession sqlSession = null;
        InputStream is = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //获取StudentMapper接口的实现类对象
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            //通过实现类对象调用方法,接受结果
            result = mapper.update(stu);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }

    @Override
    public Integer delete(Integer id) {
        SqlSession sqlSession = null;
        InputStream is = null;
        Integer result = null;
        try {
            //加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            //获取SqlSession工厂对象
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            //通过工厂对象获取SqlSession对象
            sqlSession = sqlSessionFactory.openSession(true);
            //获取StudentMapper接口的实现类对象
            StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
            //通过实现类对象调用方法,接受结果
            result = mapper.delete(id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            if (sqlSession != null) {
                sqlSession.close();
            }

            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //返回结果
        return result;
    }
}
  • 分析动态代理对象如何生成的?
    通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过getMapper()方法最终获取到org.apache.ibatis.binding.MapperProxy代理对象,然后执行功能,而这个代理对象正是MyBatis使用了JDK的动态代理技术,帮助我们生成了代理实现类对象,从而可以进行相关持久化操作
  • 分析方法是如果执行的?
    动态代理实现类对象执行方法的时候最终调用mapperMethod.execute()方法,这个方法中通过switch语句根据操作类型来判断是新增,修改,删除,查询操作,最后一步回到了MyBatis最原生的SqlSession方式执行增删改查

2.Mybatis 映射配置文件-动态SQL

  • 动态SQL指的就是SQL语句可以根据条件或者参数的不同进行动态的变化
  • 动态SQL标签
    1.<if>: 条件判断标签
    2.<where>: 条件标签,如果有动态条件,则使用该标签代替where关键字
<if test= "判断条件">
  查询条件
</if>
<select id="selectCondition" resultType="student" parameterType="student">
<!--Select * from student WHERE id=#{id} and name =#{name} and age =#{age}-->
<!-- <where>标签就是替换sql语句中的where关键字的-->
        Select * from student
        <where>
            <if test="id != null">
                id =#{id}
            </if>
            <if test="name != null">
                and name =#{name}
            </if>
            <if test="age != null">
                and age =#{age}
            </if>
        </where>
    </select>

3.<foreach>: 循环遍历标签,适用于多个参数或者的关系

<foreach collection="" open="" item="" separator="">
            获取参数
</foreach>

属性
conllection: 参数容器类型,(list-集合,array-数组)
open: 开始的SQL语句
close: 结束的SQL语句
item: 参数变量名
separator: 分隔符

<!-- 查询多个id-->
<select id="forEach" resultType="student" parameterType="list">
<!--         Select * from student where id in (1,2,3)-->
        Select * from student
        <where>
            <foreach collection="list" open="id in ( " close=")"  item="id" separator=",">
                #{id}
            </foreach>
        </where>
</select>

SQL 片段抽取>

  • 将重复性的SQL语句进行抽取,以达到复用的效果
  • <sql>: 抽取SQL语句标签
<sql id="片段唯一标识"> 抽取的SQL语句 </sql>
  • <include>: 引入SQL片段标签
<sql refid="片段唯一标识"/> 
  • 映射配置文件中的抽取与引用
    <sql id="select">Select * from student</sql>
    <!--    查询功能-->
    <select id="selectAll" resultType="student">
        <include refid="select"/>
    </select> 

3.Mybatis 核心配置文件-分页插件

  • PageHelper: 第三方分页助手,将复杂的分页操作进行封装,从而让分页功能变得非常简单
  • <plugins>: 集成插件标签
  • 分页相关API
    PageHelper: 分页助手功能类
    startPage(): 设置分页参数 参数1:当前页 参数2:当前页显示的条数
  • 分页插件实现步骤
    1.导入jar包
pagehelper-5.1.10.jar
jsqlparser-3.1.jar

2.在核心配置文件中集成分页助手插件

    <!--集成分页助手插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

3.在测试类中使用分页助手相关API实现分类功能

//通过分页助手实现分页功能
        //第一页: 显示三条
        //PageHelper.startPage(1,3);
        //第二页:显示三条,以此类推
        PageHelper.startPage(2,3);
        List<Student> list = mapper.selectAll();
        for (Student student : list) {
            System.out.println(student);
        }
        //分页相关的参数
        PageInfo<Student> info = new PageInfo<>(list);
        System.out.println("总条数:"+info.getTotal());
        System.out.println("总页数:"+info.getPages());
        System.out.println("当前页:"+info.getPageNum());
        System.out.println("每页显示的条数:"+info.getPageSize());
        System.out.println("上一页:"+info.getPrePage());
        System.out.println("下一页:"+info.getNextPage());
        System.out.println("是否是第一页:"+info.isIsFirstPage());
        System.out.println("是否是最后页:"+info.isIsLastPage());

分页插件相关参数

  • PageInfo: 封装分页相关参数的功能类

    核心方法:
    核心方法

4.Mybatis 多表操作

多表模型分类
一对一: 在任意一方建立外键,关联对方主键
一对多: 在多的一方建立外键,关联一的一方主键
多对多: 借助中间表,中间表至少两个字段,分别关联两张表的主键

一对一

  • <resultMap>: 配置字段和对象属性的映射关系标签
    id属性: 唯一标识
    type属性: 实体类对象类型
  • <id>: 配置主键映射关系标签
  • <result>: 配置非主键映射关系标签
    column属性: 表中字段名称
    property属性: 实体对象变量名称
  • <association>: 配置被包含对象的映射关系标签
    property属性: 被包含对象的变量名
    javaType属性: 被包含对象的数据类型
  • 封装类
//  空参有构造方法,get和set和toString()方法省略,
public class Card {
    private Integer id;
    private String number;
    private  Person P;
}
// 空参有参构造方法,get和set和toString()方法省略
public class Person {
    private Integer id;
    private String name;
    private Integer age;
  }
  • 数据准备
CREATE DATABASE db12;
USE db12;
CREATE TABLE person(
        id INT PRIMARY KEY AUTO_INCREMENT,
        NAME VARCHAR(20),
        age INT
);
INSERT INTO person VALUES(NULL,'张三',23);
INSERT INTO person VALUES(NULL,'李四',24);
INSERT INTO person VALUES(NULL,'王五',25);
CREATE TABLE card (
        id INT PRIMARY KEY AUTO_INCREMENT,
        number VARCHAR(30),
        pid INT,
        CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
);
INSERT INTO card VALUES(NULL,'123123',1);
INSERT INTO card VALUES(NULL,'456456',2);
INSERT INTO card VALUES(NULL,'789789',3);
  • 核心配置文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <!--映射配置文件-->
<configuration>

    <!--引入数据库连接的配置文件-->
    <properties resource="JDBC.properties"/>

    <!--继承LOG4J日志信息-->
    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

    <!--起别名-->
    <typeAliases>
        <!--<typeAlias type="com.itheima.bean" alias="***"/>-->
    <!--给bean这个包下所有的包起一个别名,作为了解-->
    <package name="com.itheima.bean"/>
    </typeAliases>

    <!--集成分页助手插件-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>

    <!--environments配置数据库环境,环境可以有多个,default属性指定使用的是哪个-->
    <environments default="mysql">
        <!--environment配置数据库环境 id属性代表唯一的标识-->
        <environment id="mysql">
            <!-- transactionManager事务的管理 type属性,采用JDBC默认的事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!--dataSource数据源信息 type属性 连接池-->
            <dataSource type="POOLED">
                <!--property获取数据库连接的数据信息-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

    <!--mappers引入映射文件-->
    <mappers>
        <!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
        <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
    </mappers>
</configuration>
  • 映射配置文件
<?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.itheima.table01.OneToOneMapper">
    <!--配置字段和实体对象属性的映射关系-->
    <resultMap id="OneToOne" type="card">
        <!--id标签是专门对主键进行配置的-->
        <id column="cid" property="id"/>
        <!--其他属性用result标签-->
        <result column="number" property="number"/>
        <!--
            association: 配置被包含对象的映射关系
            property: 被包含对象的变量名
            javaType: 被包含对象的实际的数据类型
        -->
        <association property="P" javaType="person">
            <id column="pid" property="id"/>
            <result column="name" property="name"/>
            <result column="age" property="age"/>
        </association>
    </resultMap>

    <select id="selectAll" resultMap="OneToOne">
        SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
    </select>
</mapper>
  • 测试单元
public class Test01 {
    @Test
    public void selectAll() throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
        List<Card> cards = mapper.selectAll();
        for (Card cs : cards) {
            System.out.println(cs);
        }
        sqlSession.close();
        is.close();
    }
}
  • 打印结果


    image.png

一对多

  • <collection>: 配置被包含集合对象的映射关系标签
    property属性: 被包含集合对象的变量名
    ofType属性: 集合中保存的对象数据类型
  • 封装类
//  空参有构造方法,get和set和toString()方法省略,
public class Classes {
    private Integer id; //主键id
    private  String name;   //班级名称
    private List<Student> students; //班级中所有学生对象
}
//  空参有构造方法,get和set和toString()方法省略,
public class Student {
    private Integer id; //主键id
    private String name;    //学生新明
    private Integer age;    //学生年龄
}
  • 数据准备
CREATE TABLE classes(
        id INT PRIMARY KEY AUTO_INCREMENT,
        NAME VARCHAR(20)
);
INSERT INTO classes VALUES(NULL,'一班');
INSERT INTO classes VALUES(NULL,'二班');
CREATE TABLE student(
        id INT  PRIMARY KEY AUTO_INCREMENT,
        NAME VARCHAR(30),
        age INT,
        cid INT,
        CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
);
INSERT INTO student VALUES(NULL,'张三',23,1);
INSERT INTO student VALUES(NULL,'李四',24,1);
INSERT INTO student VALUES(NULL,'王五',25,2);
INSERT INTO student VALUES(NULL,'赵六',26,2);
  • 核心配置文件,只需添加映射文件路径
    <mappers>
        <!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
        <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
        <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"></mapper>
    </mappers>
  • 映射配置文件
<?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.itheima.table02.OneToManyMapper">
    <resultMap id="OnToMany" type="classes">
        <id column="cid" property="id"/>
        <result column="cname" property="name"/>
        <!--
        collection: 配置被包含的集合对象映射关系
        property: 被包含对象的变量名
        ofType: 被包含对象的实际数据类型
        -->
        <!--这里的ofType:  指的是list集合中保存的实际数据类型-->
        <collection property="students" ofType="Student">
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
            <result column="sage" property="age"/>
        </collection>
    </resultMap>
    <select id="selectAll" resultMap="OnToMany">
        SELECT c.id cid,c.name cname, s.id sid,s.name sname,s.age sage FROM classes c,student s WHERE c.id=s.cid;
    </select>
</mapper>
  • 接口类代码
package com.itheima.table02;

import com.itheima.bean.Classes;
import java.util.List;

public interface OneToManyMapper {
    //查询全部的功能
    public abstract List<Classes> selectAll();
}
  • 测试单元代码
public class Test01 {
    @Test
    public void selectAll() throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
        List<Classes> classes = mapper.selectAll();
        for (Classes cs : classes) {
            System.out.println(cs.getId()+","+cs.getName());
            List<Student> students = cs.getStudents();
            for (Student student : students) {
                System.out.println(student);
            }
        }
        sqlSession.close();
        is.close();
    }
}
  • 测试结果
    测试结果

多对多

  • 封装类
public class Student {
    private Integer id; //主键id
    private String name;    //学生新明
    private Integer age;    //学生年龄
    private List<Course> courses;   //指当前学生所选择的课程集合
}
public class Course {
    private Integer id; //主键id
    private String name;   //课程名称
}
  • 数据准备
CREATE TABLE course(
        id INT PRIMARY KEY AUTO_INCREMENT,
        NAME VARCHAR(20)
);
INSERT INTO course VALUES(NULL,'语文');
INSERT INTO course VALUES(NULL,'数学');

CREATE TABLE stu_cr(
        id INT  PRIMARY KEY AUTO_INCREMENT,
        sid INT,
        cid INT,
        CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
        CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES(NULL,1,1);
INSERT INTO stu_cr VALUES(NULL,1,2);
INSERT INTO stu_cr VALUES(NULL,2,1);
INSERT INTO stu_cr VALUES(NULL,2,2);
  • 接口
public interface ManyToManyMapper {
    //查询全部的功能
    public abstract List<Student> selectAll();
}
  • 映射配置文件
<?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.itheima.table03.ManyToManyMapper">
    <resultMap id="manyToMany" type="student">
        <id column="sid" property="id"/>
        <result column="sname" property="name"/>
        <result column="sage" property="age"/>
        <collection property="courses" ofType="course">
            <id column="cid" property="id"/>
            <result column="cname" property="name"/>
        </collection>
    </resultMap>
    <select id="selectAll" resultMap="manyToMany">
        SELECT sc.sid ,s.name sname ,s.age sage,sc.cid ,c.name cname FROM student s,course c, stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id;
    </select>
</mapper>
  • 核心配置文件只需添加,映射配置文件路径
    <!--mappers引入映射文件-->
    <mappers>
        <!--mapper 引入指定的映射配置文件 resource属性: 指定映射配置文件的名称-->
        <mapper resource="com/itheima/one_to_one/OneToOneMapper.xml"></mapper>
        <mapper resource="com/itheima/one_to_many/OneToManyMapper.xml"></mapper>
        <mapper resource="com/itheima/many_to_many/ManyToManyMapper.xml"></mapper>
    </mappers>
  • 测试单元
  @Test
    public void selectAll() throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
        List<Student> studentList = mapper.selectAll();
        for (Student student : studentList) {
            System.out.println(student.getId()+","+student.getName()+","+student.getAge());
            List<Course> courses = student.getCourses();
            for (Course cours : courses) {
                System.out.println("/t"+cours);
            }
        }
        sqlSession.close();
        is.close();
    }
}
  • 测试结果
    测试结果
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容