Servlet/Jsp 基础

Part 1


@Description:Report of Servlet Basic, Part 1

@Date:2018.5.24

@Auther:Sujin Guo

@Reference: [1] https://blog.csdn.net/qq_26676207/article/details/51023327

​ [2] https://www.w3cschool.cn/servlet/servlet-intro.html

​ [3]《Servlet & Jsp &Spring MVC 初学指南》


[TOC]

Servlet

一、Servlet 原理

Servlet 接口定义了一套 Java 处理网络请求的规范,即如何处理 HTTP 请求,并返回结果。

Servlet 不能直接运行,要放在web容器中才能使用。与客户端打交道的是web容器(如tomcat),容器接收Http请求报文,将请求内容转化为 HttpRequest 的Java类,传入Servlet 进行逻辑操作,再将封装Http响应内容的 HttpResponse 转换为 Http 响应报文返回给客户端。

1、Servlet 生命周期

  • Servlet 通过调用 init () 方法进行初始化。初始化时,会创建ServletConfig对象,传入Servlet的成员变量。
  • Servlet 调用 service() 方法来处理客户端的请求。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并调用 doGet、doPost、doPut,doDelete 等方法。
  • Servlet 通过调用 destroy() 方法终止(结束)。
image

2、Servlet 单实例多线程

初始化:

  • 每个Servlet 只会实例化一次
  • 容器启动时实例化:在 web.xml 中通过<load-on-startup>标签进行设定,参数为数字,表示了启动的顺序,数字越小优先级越高。
  • 第一次访问时实例化:默认不配置该参数的情况下,Servlet 只有在被访问时才会实例化。

多线程:

  • 每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。
image

3、Servlet 继承关系

  • **ServletConfig **Servlet的配置信息,常用来在Servlet初始化时进行信息传递
  • Servlet 定义Servlet生命周期调用的方法:init()、service()、destroy()
  • **GenericServlet **与协议无关的Servlet,实现了Servlet和ServletConfig接口
  • **HttpServlet **基于HTTP协议的实现类
image

二、Servlet 使用

1、编写 Servlet 流程

编写一个Servlet程序大体上需要3个步骤:继承HttpServlet-->重写doGet()或者doPost()方法-->在web.xml中注册Servlet。

新语法中,可以用 @WebServlet(name = "MyServlet", urlPatterns = { "/my" }) 这样的注解来注册servlet。

2、Servlet 自定义初始化

Servlet 的自定义初始化可以通过配置 web.xml 文件,或者重写Servlet的init()方法实现。

3、常用类

(1)ServletConfig

通过Servlet 的 getServletContext 方法获得。

当Servlet容器初始化Servlet时,Servlet容器会给Servlet的init方法传入一个ServletConfig。ServletConfig中存放着Servlet的初始化信息,可通过@WebServlet或web.xml配置。

//示例
@WebServlet(name = "ServletConfigDemoServlet",
  urlPatterns = { "/servletConfigDemo" },
  initParams = {
    @WebInitParam(name="admin", value="Harry Taciak"),
    @WebInitParam(name="email", value="admin@example.com")
  }
)
方法名 说明
getInitParameter() 根据参数名获取指定初始化参数
getInitParameterNames() 获取所有初始化参数名

(2)ServletContext

通过 ServletConfig 的 getServletContext 方法获得

ServletContext 表示 Servlet 应用程序。每个Web应用程序只有一个上下文。在将一个应用程序同时部署到多个容器的分布式环境中,每台Java虚拟机上的Web应用都会有一个ServletContext对象。

通过在ServletConfig中调用getServletContext方法,可以获得ServletContext。ServletContext可以共享从应用程序中访问到的信息,并且可以动态注册Web对象。

java.lang.Object getAttribute(java.lang.String name)
java.util.Enumeration<java.lang.String> getAttributeNames()
void setAttribute(String name, Object object)
void removeAttribute(String name)

三、Servlet 程序示例

  • 第一个 Servlet(编写 Servlet 流程)
  • Servlet 生命周期(展示 init、destroy、service 函数的作用)
  • 获取 Servlet 初始化参数(配置Servlet初始化参数并获取)

Request & Response

一、Request & Response API

1、ServletRequest

对于每一个HTTP请求,Servlet容器都会创建一个 ServletRequest 实例,并将它传给Servlet的Service方法。
ServletRequest 封装了关于这个请求的信息。

getParameter() 是最常用的方法,可以获取表单(form)的参数值。

方法名 说明
getContentLength() 返回请求主体的字节数。如果不知道字节长度,这个方法就会返回−1。
getContentType() 返回请求主体的MIME类型,如果不知道类型,则返回null
getParameter(String name) 返回指定请求参数的值。
getProtocol() 返回这个HTTP请求的协议名称和版本。

2、HttpServletRequest

HttpServletRequest 继承了 ServletRequest

方法名 说明
getContextPath() 返回表示请求上下文的请求URI部分
getCookies() 返回一个Cookie对象数组
getMethod() 返回生成这个请求的HTTP方法名称。
getQueryString() 返回请求URL中的查询字符串
getSession() 返回与这个请求相关的会话对象。如果没有,将创建一个新的会话对象。
getSession(boolean create) 返回与这个请求相关的会话对象。如果有,并且create参数为True,将创建一个新的会话对象。

3、ServletResponse

ServletResponse接口表示一个Servlet响应。在调用Servlet的Service方法前,Servlet容器首先创建一个ServletResponse,并将它作为第二个参数传给Service方法。ServletResponse隐藏了向浏览器发送响应
的复杂过程。

方法名 说明
getWriter 获取字符输出流
setContentType 设置方法体内容格式,如:text/html
getOutputStream 获取二进制输出流

4、HttpServletResponse

HttpServletResponse 继承了 ServletResponse

方法名 说明
addCookie(Cookie cookie) 给这个响应对象添加一个cookie
addHeader(String name, String value) 给这个响应对象添加一个header
sendRedirect(String location) 发送一条响应码,将浏览器跳转到指定的位置

二、Requset & Response 的使用

1、转发和重定向

网页跳转有两种方式重定向和服务器内部转发。Forward 和 Redirect 的区别。

Forward:

request.getRequestDispatcher("/somePage.jsp").forward(request, response); 
  1. servlet将请求交给Web应用的另一部分RequestDispatcher.forward(request,response) 方法的调它们属于同一个访问请求和响应过程
  2. 浏览器以正常方式得到响应,把它显示给用户(在浏览器的地址栏上没有变化,用户不知道发生过请求分派)

Redirect:

response.sendRedirect(String location);
  1. servlet在响应上请求sendRedirect(aString)
  2. HTTP响应有一个状态码“301”,和一个“Location”首部,这个首部值是一个URL
  3. 浏览器得到响应,发现“301”状态码,并寻找“Location”首部,由此建立一个新的请求(在浏览器的地址栏里URL改变了)

区别:

  1. 重定向跳转过程发生在客户端,客户端发送了两次请求。转发跳转过程发生在服务端,客户端不能察觉到转发过程。
  2. 由于重定向要经过两次请求来回,所以转发速度更快,并且可以继续使用 request、response 对象。
  3. 重定向可以将页面转到外网。

2、相对路径和绝对路径

URL的写法也有2种方式:绝对路径和相对路径。相对路径使用..即可,而绝对路径重定向需要依赖request.getContextPath() 方法取得上下文环境,而服务器内部转发中的斜线就表示项目的根目录。

3、获取请求信息

获取 http 请求头信息

获取 http 表单信息:request.getParameter(String name)

4、设置响应信息

设置和获取 http 响应头信息:response.addHeader(String name, String value)

设置响应内容:response.getWriter()

三、Requset & Response 程序示例

  • Servlet 表单提交与展示(获取请求信息、设置相应信息、转发 Forward)
  • Servlet 路径跳转(绝对路径和相对路径)

Part 2


@Description:Report of Servlet Basic, Part 2

@Date:2018.6.1

@Auther:Sujin Guo

@Reference: [1] 《Servlet & Jsp &Spring MVC 初学指南》

​ [2] https://www.cnblogs.com/raozihao/p/7711582.html


JSP

JSP 基础

1、概论

在 jsp 出现前,Servlet 必须在 Writer 中拼接 html,使得控制层和显示层混在一起。jsp 则实现了控制层和显示层的分离,让 Servlet 只关注业务逻辑,jsp 控制页面展示。

JSP 的生命周期:

JSP 页面本质上是一个 Servlet。当一个JSP页面第一次被请求时,Servlet/JSP 容器主要做以下两件事情:

  1. 转换JSP页面到JSP页面实现类,该实现类是一个实现 javax.servlet.jsp.JspPage 接口或子接口javax.servlet.jsp.HttpJspPage 的Java类。JspPage是 javax.servlet.Servlet 的子接口,这使得每一个JSP页面都是一个Servlet。该实现类的类名由Servlet/JSP容器生成。如果出现转换错误,则相关错误信息将被发送到客户端。
  2. 如果转换成功,Servlet/JSP 容器随后编译该 Servlet 类,并装载和实例化该类,像其他正常的 Servlet 一样执行生命周期操作。

JSP 页面也可以被配置为启动时加载。当JSP文件修改时,容器会自动重新编译,无需重启tomcat。

注释:

java 注释,不会发送给客户端。

<%-- retrieve products to display --%>

html 注释,会发送给客户端

<!-- [comments here] -->

2、JSP 中九大隐式对象

Servlet容器会传递几个对象给它运行的Servlet。例如,可以通过Servlet的service方法拿到HttpServletRequest和HttpServletResponse对象,以及可以通过init方法访问到ServletConfig对象。此外,可以通过调用HttpServletRequest对象的getSession方法访问到HttpSession对象。

在JSP中,可以通过使用隐式对象来访问上述对象。表3.1所示为JSP隐式对象。

对象 类型
request javax.servlet.http.HttpServletRequest
response javax.servlet.http.HttpServletResponse
out javax.servlet.jsp.JspWriter
session javax.servlet.http.HttpSession
application javax.servlet.ServletContext
config javax.servlet.ServletConfig
pageContext javax.servlet.jsp.PageContext
page javax.servlet.jsp.HttpJspPage
exception java.lang.Throwable

可以直接在JSP内嵌java语句中使用这些对象,如:

<% String userName = request.getParameter("userName"); %>

PageContext:

PageContext 有设置和获取属性的方法。属性值可被存储在4个范围之一:页面、请求、会话和应用程序(PAGE_SCOPE、REQUEST_ SCOPE、SESSION_SCOPE和APPLICATION_SCOPE)。页面范围是最小范围,这里存储的属性只在同一个JSP页面可用。请求范围是指当前的ServletRequest中。会话范围指当前的HttpSession中。应用程序范围指应用的ServletContext中。

public abstract void setAttribute(String name, Object value, int scope)

案例:jsp 调用隐式对象页面

(1)request 对象

request 对象是 javax.servlet.http.HttpServletRequest 对象的一个实例。每当客户端请求页面时,JSP引擎将创建一个新对象来表示该请求。

request对象提供了获取包括表单数据,Cookie,HTTP方法等HTTP头信息的方法。

(2)response 对象

response对象是javax.servlet.http.HttpServletResponse对象的一个实例。就像服务器创建request对象一样,它还创建一个对象来表示对客户端的响应。

response对象还定义了处理创建新HTTP头的接口。通过此对象,JSP程序员可以添加新的Cookie或日期戳,HTTP状态代码等。

(3)out 对象

out隐式对象是javax.servlet.jsp.JspWriter对象的一个实例,用于在响应中发送内容。可以动态输出页面内容,如动态打印表格。

初始化JspWriter对象根据页面是否缓存而不同地实例化。缓冲可以通过使用page指令的buffered ='false'属性来关闭。

JspWriter对象包含与java.io.PrintWriter类大部分相同的方法。但是,JspWriter还有一些额外的方法用来处理缓冲。与PrintWriter对象不同,JspWriter会抛出IOExceptions异常。

(4)session 对象

session对象是javax.servlet.http.HttpSession的一个实例,其行为与Java Servlet下的会话对象行为完全相同。session对象用于跟踪客户端请求之间的客户端会话。

(5)application 对象

application 对象是生成的 Servlet 的 ServletContext 对象的直接包装,实际上是javax.servlet.ServletContext对象的一个实例。

application对象是JSP页面在其整个生命周期中的表示。 当JSP页面被初始化时,将创建此对象,并且在JSP页面被jspDestroy()方法删除时 application 对象也将被删除。

通过向 application 对象添加属性值,可以确保组成 Web 应用程序的所有 JSP 文件都可以访问它。

(6)config 对象

config 对象是 javax.servlet.ServletConfig 的实例化,是生成的 servlet 的 ServletConfig 对象周围的直接包装。

(7)pageContext 对象

pageContext 对象是 javax.servlet.jsp.PageContext 对象的一个实例。pageContext 对象用于表示整个JSP页面。

(8)page 对象

page对象是对该页面实例的实际引用。可以认为它是表示整个JSP页面的对象。

page对象是this对象的直接同义词。

(9)exception 对象

exception对象是一个包含上一页抛出的异常的包装器。它通常用于生成对错误条件的适当响应。

3、JSP 中的四个作用域

所谓“作用域”就是“信息共享的范围”,也就是说一个信息能够在多大的范围内有效。JSP中九个内置对象及其相应所属作用域如下表:

对象 所属作用域 作用域描述
request request 在当前请求中有效
response page 在当前页面有效
out page 在当前页面有效
session session 在当前会话中有效
application application 在所有应用程序中有效
config page 在当前页面有效
pageContext page 在当前页面有效
page page 在当前页面有效
Exception page 在当前页面有效

由上图可知,这九个内置对象都有相应的作用域,作用域在这里的作用就是限定对象的生命周期。如果跳出了当前对象的作用域,该对象的信息就不能再被访问。

JSP指令

指令是JSP语法元素的第一种类型。它们指示JSP转换器如何翻译JSP页面为Servlet。

1、page指令

<%@page attribute1="value1" attribute2="value2" ... %>

page 指令有如下属性:

属性 说明
import 定义一个或多个本页面中将被导入和使用的java类型。
session 本页面是否加入会话管理。默认值为True。
buffer 定义隐式对象out的缓冲大小。必须以KB后缀结尾。默认大小为8KB或更大(取决于JSP容器)。该值可以为none,这意味着没有缓冲,所有数据将直接写入PrintWriter。
autoFlush 默认值为True。若值为True,则当输出缓冲满时会自写入输出流。而值为False,则仅当调用隐式对象的flush方法时,才会写入输出流。因此,若缓冲溢出,则会抛出异常。
isThreadSafe 定义该页面的线程安全级别。不推荐使用 JSP 参数,因为使用该参数后,会生成一些 Servlet容器已过期的代码。
info 返回调用容器生成的 Servlet 类的 getServletInfo 方法的结果
errorPage 定义当出错时用来处理错误的页面。
isErrorPage 标识本页是一个错误处理页面。
contentType 定义本页面隐式对象response的内容类型,默认是text/html。
pageEncoding 定义本页面的字符编码,默认是ISO-8859-1。
isELIgnored 配置是否忽略EL表达式。EL是Expression Language的缩写。
language 定义本页面的脚本语言类型,默认是 Java,这在 JSP 2.2 中是唯一的合法值。
extends 定义JSP实现类要继承的父类。这个属性的使用场景非常罕见,仅在特殊理由下使用。
deferredSyntax AllowedAsLiteral 定义是否解析字符串中出现“#{”符号,默认是False。“{# ”是一个表达式语言的起始符号。
trimDirective Whitespaces 定义是否不输出多余的空格/空行,默认是False。

2、include 指令

include 指令的语法如下:

<%@include file="url"%>

include 指令引入 copyright.jspf 文件,include所在的行被copyright.jspf 文件内容代替。按照惯例,以JSPF为扩展名的文件代表JSP fragement 或 JSP segment。include指令也可以包含静态HTML文件。

<html>
  <head><title>Including a file</title></head>
  <body>
    This is the included content: <hr/>
    <%@ include file="copyright.jspf"%>
  </body>
</html>

脚本元素

一个脚本程序是一个Java代码块,以<%符号开始,以%>符号结束。

1、表达式

每个表达式都会被JSP容器执行,并使用隐式对象out的打印方法输出结果。表达式以“<%=”开始,并以“%>”结束。

Today is <%=java.util.Calendar.getInstance().getTime()%>
<!-- 上下两段代码等效 -->
Today is <% out.print(java.util.Calendar.getInstance().getTime()); %>

2、声明

可以声明能在JSP页面中使用的变量和方法。声明以“<%!”开始,并以“%>”结束。

<%!
public String getTodaysDate() {
return new java.util.Date();
}%>
<html>
  <head><title>Declarations</title></head>
  <body>
  Today is <%=getTodaysDate()%>
  </body>
</html>

可以使用声明来重写JSP页面,实现类的init和destroy方法。通过声明jspInit方法,来重写init方法。通过声明jspDestroy方法,来重写destory方法。在创建和销毁JSP页面时会分别调用jspInit和jspDestroy方法。

3、禁用脚本元素

随着JSP 2.0对表达式语言的加强,推荐的实践是:在JSP页面中用EL访问服务器端对象且不写Java代码。因此,从JSP 2.0起,可以通过在部署描述符中的<jspproperty-group>定义一个scripting-invalid元素,来禁用脚本元素。

<jsp-property-group>
  <url-pattern>*.jsp</url-pattern>
  <scripting-invalid>true</scripting-invalid>
</jsp-property-group>

动作

动作是第三种类型的语法元素,它们被转换成Java代码来执行操作,如访问一个Java对象或调用方法。下面讨论所有JSP容器支持的标准动作。除标准外,还可以创建自定义标签执行某些操作。

1、useBean

useBean将创建一个关联Java对象的脚本变量。这是早期分离的表示层和业务逻辑的手段。随着其他技术的发展,如自定义标签和表达语言,现在很少使用useBean方式。

它创建一个java.util.Date实例,并赋值给名为today的脚本变量,然后在表达式中使用。访问这个页面会显示系统当前时间:

<jsp:useBean id="today" class="java.util.Date"/>
<%=today%>

2、setProperty 和 getProperty

setProperty动作可对一个Java对象设置属性,而getProperty则会输出Java对象的一个属性。

//Employee 实体
public class Employee {
  private String id;
  private String firstName;
  private String lastName;
  ... getter and setter 函数 ...
}
<!-- 用setProperty设置实体属性,getProperty获取实体属性 -->
<body>  
  <jsp:useBean id="employee" class="app03a.Employee"/>
  <jsp:setProperty name="employee" property="firstName"value="Abigail"/>
  First Name: <jsp:getProperty name="employee" property="firstName"/>
</body>

3、include

include动作用来动态地引入另一个资源。可以引入另一个JSP页面,也可以引入一个Servlet或一个静态的HTML页面。

<body>
  <jsp:include page="jspf/menu.jsp">
    <jsp:param name="text" value="How are you?"/>
  </jsp:include>
</body>

include 指令和 include 动作的不同:

  1. 对于include指令,资源引入发生在 JSP 容器将页面转换为生成的 Servlet 时。而对于include动作,资源引入发生在请求页面时。因此,使用include动作是可以传递参数的,而include指令不支持。
  2. 第二个不同是,include指令对引入的文件扩展名不做特殊要求。但对于include动作,若引入的文件需以JSP页面处理,则其文件扩展名必须是JSP。若使用.jspf为扩展名,则该页面被当作静态文件。

4、forward

forward将当前页面转向到其他资源。下面代码将从当前页转向到 login.jsp 页面:

<jsp:forward page="jspf/login.jsp">
  <jsp:param name="text" value="Please login"/>
</jsp:forward>

错误处理

当 jsp 页面抛出异常时,用户将看到一个精心设计的网页解释发生了什么,而不是一个用户无法理解的错误信息。

page指令定义错误页面:

<%@page isErrorPage="true"%>
<html>
<head><title>Error</title></head>
  <body>
  An error has occurred. <br/>
  Error message:
  <% out.println(exception.toString()); %>
  </body>
</html>

其他页面指向错误页面,也用page指令定义:

<%@page errorPage="errorHandler.jsp"%>
Deliberately throw an exception
<% Integer.parseInt("Throw me"); %>

JSP:表达式语言

1、语法

JSP 2.0最重要的特性之一就是表达式语言(EL),JSP用户可以用它来访问应用程序数据。

表达式格式:

EL表达式以 ${ 开头,并以 } 结束。EL表达式的结构如下:

格式:${expression}
如:${x+y}

获取对象属性:

为了获取对象属性,可以用下列两种方式:

${object["propertyName"]}
${object.propertyName}

嵌套使用的情况:

${pageContext["request"]["servletPath"]}
${pageContext.request["servletPath"]}
${pageContext.request.servletPath}
${pageContext["request"].servletPath}

2、EL隐式对象

在JSP页面中,可以利用JSP脚本来访问JSP隐式对象。但是,在免脚本的JSP页面中,则不可能访问这些隐式对象。EL允许通过提供一组它自己的隐式对象来访问不同的对象。EL隐式对象如下表所示:

对象 描述
pageContext 这是当前JSP的javax.servlet.jsp.PageContext
initParam 这是一个包含所有环境初始化参数,并用参数名作为key的Map
param 这是一个Map,可以获取请求提交的参数,如登录时的 username、password。
paramValues 和param类似,但Map中key对应的value是一个字符串数组,可返回同一个param名称对应的多个属性。
header 这是一个Map,可以获取请求头的属性,如accept、connect。
headerValues 和header类似,但Map中key对应的value是一个字符串数组,可返回同一个header名称对应的多个属性。
cookie 这是一个包含了当前请求对象中所有Cookie对象的Map。Cookie名称就是key名称,并且每个key都映射到一个Cookie对象
applicationScope 这是一个包含了ServletContext对象中所有属性的Map,并用属性名称作为key
sessionScope 这是一个包含了HttpSession对象中所有属性的Map,并用属性名称作为key
requestScope 这是一个Map,其中包含了当前HttpServletRequest对象中的所有属性,并用属性名称作为key
pageScope 这是一个Map,其中包含了全页面范围内的所有属性。属性名称就是Map的key

在servlet/JSP编程中,有界对象是指在以下对象中作为属性的对象:PageContext、ServletRequest、HttpSession或者ServletContext。隐式对象sessionScope、requestScope和pageScope与applicationScope相似。但是,其范围分别为session、request和page。

3、配置 EL

有了EL、JavaBeans和定制标签,就可以编写免脚本的JSP页面了。JSP 2.0及其更高的版本中还提供了一个开关,可以使所有的JSP页面都禁用脚本。

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <scripting-invalid>true</scripting-invalid>
  </jsp-property-group>
</jsp-config>

另一方面,在有些情况下,可能还会需要在应用程序中取消EL。例如,正在使用与JSP 2.0兼容的容器,却尚未准备升级到JSP 2.0,那么就需要这么做。在这种情况下,可以关闭EL表达式的计算。

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <el-ignored>true</el-ignored>
  </jsp-property-group>
</jsp-config>

JSTL

JSP 标准标签库(JavaServer Pages Standard Tag Library,JSTL)是一个定制标签库的集合,用来解决像遍历Map或集合、条件测试、XML处理,甚至数据库访问和数据操作等常见的问题。

Demo

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