Java实现验证码制作

Java实现验证码制作


java.jpg

第一章 概述

1.1 验证码概述

  • 为什么要使用验证码
  • 什么是验证码
  • 使用Servlet实现验证码
  • 使用开源组件实现验证码
  • 验证码的发展

如图可以发现计算机也可以通过传递URL参数等来执行登录操作

没有验证码带来的问题

  • 对特定用户不断登录破解密码
  • 对某个网站创建账户
  • 对某个网站提交垃圾数据
  • 对某个网站刷票

我们要通过验证码, 由用户肉眼识别其中的验证码信息, 从而区分用户是人还是计算机

验证码的定义

  • 验证码(captcha):是一种区分用户是人还是计算机的公共全自动程序.
  • 作用:可以防止恶意破解密码,刷票,论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试.
  • 实际上用验证码是现在很多网站通行的方法,我们利用比较简易的方式实现了这个功能.

第二章 使用Servlert实现验证码

2.1 使用Servlert实现验证码的步骤

验证码包含两部分:

  1. 输入框
  2. 显示验证码的图片
    那么验证码图片是如何获取的?

网页显示验证码

  • <input type="text" id="verifyCode" name="verifyCode" size=6"" />
  • <img alt="验证码" id="safecode" src=<%=request.getContextPath()%>/servlet/ImageServlet">

生成图片

  • 生成图片用到的类
  1. BufferedImage图像数据缓冲区
  2. Graphics绘制图片
  3. Color获取颜色
  4. Random生成随机数
  5. ImageIO输出图片

生成图片的实现类

  • ImageServlet类
  1. 定义BufferedImage对象
  2. 获得Graphics对象
  3. 通过Random产生随机验证码信息
  4. 使用Graphics绘制图片
  5. 记录验证码信息到session中
  6. 使用ImageIO输出图片

校验验证码是否正确

  • LoginServlet类
  1. 获取页面验证码
  2. 获取session保存的验证码
  3. 比较验证码
  4. 返回校验结果

使用Servlet实现验证码流程


2.2 验证码的代码实现

    // /servlet/ImageServlet
    protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        BufferedImage bi = new BufferedImage(68, 22, BufferedImage.TYPE_INT_RGB);
        Graphics gs = bi.getGraphics();
        Color c = new Color(196, 162, 129);
        gs.setColor(c);
        gs.fillRect(0,0,68,22);

        char[] ch = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
        Random ran = new Random();
        int len = ch.length,index;
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 4; i++) {
            index = ran.nextInt(len);
            gs.setColor(new Color(Test.getCorrectColor(196),Test.getCorrectColor(162),Test.getCorrectColor(129)));
            gs.drawString(ch[index] + "", (15 * i) + 8, 18);
            sb.append(ch[index]);
        }
        request.getSession().setAttribute("piccode", sb.toString());
        ImageIO.write(bi, "JPG", response.getOutputStream());
    }
    
    //Test.java
    public static int getCorrectColor(int a){
        Random ran = new Random();
        int temp = ran.nextInt(256);
        if (0 <= a - temp && a - temp < 40) {
            temp = a - 40;
        }
        if (a - temp < 0 && temp - a < 40) {
            temp = a + 40;
        }
        return temp;
    }

index.jsp

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
    <title>验证码制作</title>
      <script type="text/javascript">
          function flush_() {
              document.getElementById("captcha").src = "<%=request.getContextPath()%>/servlet/ImageServlet?d="+new Date();
              alert("88");
          }
      </script>
    </head>
    <body>
    验证码: <input type="text" name="captcha" />
    <img alt="captcha" id="captcha" src="<%=request.getContextPath()%>/servlet/ImageServlet" />
    <a href="javascript:
    (function(){document.getElementById('captcha').src='<%=request.getContextPath()%>/servlet/ImageServlet?d='+new Date();})();">看不清楚</a>
    </body>
    </html>
    <%--这里提供了两种js函数定义方法, 其中匿名函数的定义方式与java并不相同.
    这里采用的是(function(a){...})(a)这种格式.前一个()为方法体的定义, 后一个()表示传参并执行.
    匿名函数的缺点在与对一些需要重新解除函数绑定的事件类动作无法解绑?个人理解, 并不懂.
    同时, 在方法体中由于不能使用""进行书写, 则选择使用''代替, 或者使用"字符转义代替.
    在方法体末端的"?d=+"new Date()", 表示通过当前时间来改变网页请求, 从而实现刷新.
    否则浏览器缓存的原因会导致不刷新.
    --%>

2.3 验证码的校验

index.jsp

<form action="<%=request.getContextPath()%>/servlet/LoginServlet" method="post">
    验证码: <input type="text" name="captchaNo" />
    <img alt="captcha" id="captcha" src="<%=request.getContextPath()%>/servlet/ImageServlet" />
    <a href="javascript:(function(){document.getElementById('captcha').src='<%=request.getContextPath()%>/servlet/ImageServlet?d='+new Date();})();">看不清楚</a>
    <div><input type="submit" value="提交" /></div>
</form>

LoginServlet.java

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String captcha = request.getParameter("captchaNo").toUpperCase();
    System.out.println(captcha);
    System.out.println(request.getSession().getAttribute("piccode"));
    if (request.getSession().getAttribute("piccode").equals(captcha)) response.sendRedirect("/success.jsp");
    else response.sendRedirect("/index.jsp");
    System.out.println("验证完成===========");
}

Test.java

public static int getCorrectColor(int a){
    Random ran = new Random();
    int i = ran.nextInt(41) + (255 - a - 20);
    i = i > 0 ? i : 0;
    i = i > 255 ? 255 : i;
    System.out.print(i+" ");
    return i;
}

第三章 使用Jcaptcha组件实现验证码

  • Jcaptcha: 一个用来生成图形验证码的Java开源组件,使用非常简单方便. 与Spring组合使用,可产生多种形式的验证码.
  • Kaptcha: 一个非常使用的验证码生成工具, 它是可以配置的, 可以生成各种各样的验证码.

Jcaptcha组件实现验证码实例

项目案例

  • JSP禁用缓存的方式 response.setHeader( "Pragma", "no-cache" ); setDateHeader("Expires", 0);的用法和什么意思

JSP禁用缓存的方式 使用服务器端控制AJAX页面缓存: response.setHeader( "Pragma", "no-cache" ); response.addHeader( "Cache-Control", "must-revalidate" ); response.addHeader( "Cache-Control", "no-cache" ); response.addHeader( "Cache-Control", "no-store" ); response.setDateHeader("Expires", 0); 单纯的使用 xmlhttp.setRequestHeader("Cache-Control","no-cache")无效。

Cache-Control头域 Cache-Control指定请求和响应遵循的缓存机制。 在请求消息或响应消息中设置Cache-Control并不会修改另一个消息处理过程中的缓存处理过程。 请求时的缓存指令包括no-cache、no-store、max-age、max-stale、min-fresh、only-if-cached. 响应消息中的指令包括public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age。 各个消息中的指令含义如下: Public指示响应可被任何缓存区缓存。   Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。   no-cache指示请求或响应消息不能缓存   no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。   max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。   min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。   max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。

禁用IE缓存 HTTP消息报头包括普通报头、请求报头、响应报头、实体报头。 普通报头中的Cache-Control用于指定缓存指令,缓存指令是单向的(响 应中出现的缓存指令在请求中未必会出现).且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。 请求时的缓存指令包括:no-cache(用于指示请示或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached; 响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage。

例:为了指示IE浏览器(客户端)不要缓存页面,服务器端的jsp程序可以编写如下: response.setHeader(“Cache-Control”, “no-cache”); //response.setHeader(“Pragma”, “no-cache”);作用相当于上行代码,通常两者合用

Expires实体报头域给出响应过期的日期和时间。 为了让代理服务器或浏览器在一段时间以后更新缓存中(再次访问曾访问过的页面时,直接从缓存中加载,缩短响应时间和降低服务器负载)的页面, 我们可以使用Expires实体报头域指定页面过期时间。 例:Expires:Thu,15 Sep 2006 16:23:12 GMT HTTP1.1的客户端和缓存必须将其他非法的日期格式(包括0)看作已经过期。如:为了让浏览器不要缓存页面,也可以利用Expires实体报关域,设置为0,jsp程序如下: response.setDateHeader(“Expires”, “0”);

jcaptcha使用默认样式生成的验证码比较难以识别,所以需要自定义验证码的样式,包括,背景色、背景大小、字体、字体大小、生成的字符数等。相对与kaptcha比较复杂。

纯代码实现jcaptcha验证码

1、首先创建一个javaWeb工程添加jcaptcha包和它所依赖的包.

commons-collections-3.2.jar
commons-logging-1.2.jar
jcaptcha-1.0-all.jar

2、创建一个jcaptcha单例的Service类,这里是设置验证码样式的关键部分,代码如下:

package cn.v5cn.jcaptchatest.custom;
 
import java.awt.Font;
 
import com.octo.captcha.CaptchaFactory;
import com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.word.FileDictionary;
import com.octo.captcha.component.word.wordgenerator.ComposeDictionaryWordGenerator;
import com.octo.captcha.engine.GenericCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.octo.captcha.service.multitype.GenericManageableCaptchaService;
 
public class CaptchaServiceSingleton {
    private static ImageCaptchaService service = null;
 
    public static ImageCaptchaService getService(){
        if(service == null)
            service = generatorCaptchaService();
        return service;
    }
    /**
     * 根据SpringBean的配置文件编写的代码实现
     * */
    public static ImageCaptchaService generatorCaptchaService(){
        //生成随机颜色,参数分别表示RGBA的取值范围
        RandomRangeColorGenerator textColor = new RandomRangeColorGenerator(new int[]{0,255},new int[]{0,180},new int[]{0,210},new int[]{255,255});
        //随机文字多少和颜色,参数1和2表示最少生成多少个文字和最多生成多少个
        RandomTextPaster randomTextPaster = new RandomTextPaster(4, 5, textColor,true);
        //生成背景的大小这里是宽85高40的图片,也可以设置背景颜色和随机背景颜色,这里使用默认的白色
        UniColorBackgroundGenerator colorbgGen = new UniColorBackgroundGenerator(85,40);
        //随机生成的字体大小和字体类型,参数1和2表示最小和最大的字体大小,第三个表示随机的字体
        RandomFontGenerator randomFontGenerator = new RandomFontGenerator(20, 25, new Font[]{new Font("Arial", 0, 10),new Font("Tahoma",0,10)});
        //结合上面的对象构件一个从文本生成图片的对象
        ComposedWordToImage cwti = new ComposedWordToImage(randomFontGenerator,colorbgGen,randomTextPaster);
        //随机文本的字典,这里是使用jcaptcha-1.0-all.jar中的文本字典,字典名称为toddlist.properties
        ComposeDictionaryWordGenerator cdwg = new ComposeDictionaryWordGenerator(new FileDictionary("toddlist"));
 
        GimpyFactory gf = new GimpyFactory(cdwg, cwti);
 
        GenericCaptchaEngine gce = new GenericCaptchaEngine(new CaptchaFactory[]{gf});
        //返回一个Service对象,这里180是验证码存在的时间,单位是秒,200000是最大存储大小
        return new GenericManageableCaptchaService(gce,180,200000,75000);
    }
}

3、创建一个生成验证码的Servlet,代码如下:

package cn.v5cn.jcaptchatest.custom;
 
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
 
public class CustomServlet extends HttpServlet {
 
    private static final long serialVersionUID = 169310818225761427L;
     
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        byte[] captChallengeAsJpeg = null;
         
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
         
        String captchaId = req.getSession().getId();
        BufferedImage challenge = CaptchaServiceSingleton.getService().getImageChallengeForID(captchaId,req.getLocale());
         
        JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
        jpegEncoder.encode(challenge);
         
        captChallengeAsJpeg = jpegOutputStream.toByteArray();
         
         resp.setHeader("Cache-Control", "no-store");
         resp.setHeader("Pragma", "no-cache");
         resp.setDateHeader("Expires", 0);
         resp.setContentType("image/jpeg");
          
         ServletOutputStream respOutputStream = resp.getOutputStream();
         respOutputStream.write(captChallengeAsJpeg);
         respOutputStream.flush();
         respOutputStream.close();
    }
}

4、在Web.xml中注册这个Servlet,代码如下:

<servlet>
    <servlet-name>generateValidateCode</servlet-name>
    <servlet-class>cn.v5cn.jcaptchatest.custom.CustomServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>generateValidateCode</servlet-name>
    <url-pattern>/cgvc</url-pattern>
  </servlet-mapping>

5、编写一个使用验证码的页面,代码如下:

<form action="valiServlet" method="post">
    <input type="text" name="customgvc">
    ![](cgvc)
    <input type="submit" value="提交">
</form>

6、编写一个验证Servlet并在web.xml中注册,代码分别如下:

package cn.v5cn.jcaptchatest.custom;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class ValidateServlet extends HttpServlet {
 
    private static final long serialVersionUID = -7173743572400866269L;
     
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String captchaId = req.getSession().getId();
         
        String validateCode = req.getParameter("customgvc");
         
        boolean validateResult = CaptchaServiceSingleton.getService().validateResponseForID(captchaId, validateCode);
        if(validateResult)
            resp.sendRedirect("success.html");
        else
            resp.sendRedirect("fail.html");
    }
}
<servlet>
    <servlet-name>validatServlet</servlet-name>
    <servlet-class>cn.v5cn.jcaptchatest.custom.ValidateServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>validatServlet</servlet-name>
    <url-pattern>/valiServlet</url-pattern>
  </servlet-mapping>

第四章 使用Kaptcha组件实现验证码制作

4.1 字母数字组合验证码的实现

web.xml

    <!--kaptcha验证码配置-->
    <servlet>
        <servlet-name>kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
        <init-param>
            <param-name>kaptcha.border</param-name>
            <param-value>no</param-value>
        </init-param>
        <init-param>
            <param-name>kaptcha.textproducer.font.color</param-name>
            <param-value>black</param-value>
        </init-param>
        <init-param>
            <param-name>kaptcha.textproducer.char.space</param-name>
            <param-value>5</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>kaptcha</servlet-name>
        <url-pattern>/kaptcha.jpg</url-pattern>
    </servlet-mapping>
    <!--
    kaptcha.border:是否显示边框。
    kaptcha.textproducer.font.color:字体颜色
    kaptcha.textproducer.char.space:字符间距
    更多的属性设置可以在com.google.code.kaptcha.Constants类中找到。其中包括:
    kaptcha.border.color:边框颜色
    kaptcha.border.thickness:边框宽度
    kaptcha.textproducer.char.length:产生字符的长度
    kaptcha.textproducer.font.size:产生字符的大小
    kaptcha.image.width:产生图片的宽度
    kaptcha.image.height:产生图片的高度
    -->

index.jsp

    <form action="${pageContext.request.contextPath}/kaptcha" method="post">
        <input type="text" name="kaptchaValidate">
        <img id="vcode"onclick="(function() {document.getElementById('vcode').src
        ='${pageContext.request.contextPath}/kaptcha.jpg?'+new Date();

        })()" title="点击更换" style="vertical-align: middle;" alt="验证图片"
        src="${pageContext.request.contextPath}/kaptcha.jpg" height="35" width="80">
        <input type="submit" value="提交">
    </form>

KaptchaValidateServlet.java

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
        String validate = request.getParameter("kaptchaValidate");
        String validateCode = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);

        if (validate ==null || validateCode == null) response.sendRedirect("/index.jsp");
        else if (!validateCode.equals(validate)) response.sendRedirect("/index.jsp");
        else response.sendRedirect("/success.jsp");
    }

4.2 Kaptcha的详细配置

<!--kaptcha验证码配置-->
    <servlet>
        <servlet-name>kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
        <init-param>
            <description>图片边框, yes or no</description>
            <param-name>kaptcha.border</param-name>
            <param-value>yes</param-value>
        </init-param>
        <init-param>
            <description>边框颜色, white,black,blue...</description>
            <param-name>kaptcha.border.color</param-name>
            <param-value>blue</param-value>
        </init-param>
        <init-param>
            <description>边框厚度,正整数</description>
            <param-name>kaptcha.border.thickness</param-name>
            <param-value>2</param-value>
        </init-param>
<!--        <init-param>
            <description>图片宽度</description>
            <param-name>kaptcha.image.width</param-name>
            <param-value>80</param-value>
        </init-param>
        <init-param>
            <description>图片高度</description>
            <param-name>kaptcha.image.height</param-name>
            <param-value>35</param-value>
        </init-param>-->
<!--       <init-param>
            <description>图片实现类</description>
            <param-name>kaptcha.producer.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.DefaultKaptcha</param-value>
        </init-param>-->
        <init-param>
            <description>文本实现类, 类似文本字符集</description>
            <param-name>kaptcha.textproducer.impl</param-name>
            <param-value>ArithmeticIdentify</param-value>
            <!--<param-value>ChineseTest</param-value>-->
        </init-param>
<!--        <init-param>
            <description>文本集合,验证码值从此集合中获取</description>
            <param-name>kaptcha.textproducer.char.string</param-name>
            <param-value>我们就是这样实现验证码制作然后怎么呢文本类似大小设置长度提交进行尽兴金星影响营养</param-value>
        </init-param>-->
        <init-param>
            <description>设置字体</description>
            <param-name>kaptcha.textproducer.font.names</param-name>
            <param-value>Sim Sun</param-value>
        </init-param>
<!--        <init-param>
            <description>设置字体大小</description>
            <param-name>kaptcha.textproducer.font.size</param-name>
            <param-value>16</param-value>
        </init-param>-->
        <init-param>
            <description>字体颜色</description>
            <param-name>kaptcha.textproducer.font.color</param-name>
            <param-value>blue</param-value>
        </init-param>
        <init-param>
            <description>文字间隔</description>
            <param-name>kaptcha.textproducer.char.space</param-name>
            <param-value>10</param-value>
        </init-param>
<!--        <init-param>
            <description>干扰实现类</description>
            <param-name>kaptcha.noise.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.DefaultNoise</param-value>
        </init-param>-->
        <init-param>
            <description>干扰颜色</description>
            <param-name>kaptcha.noise.color</param-name>
            <param-value>yellow</param-value>
        </init-param>
<!--        <init-param>
            <description>背景实现类</description>
            <param-name>kaptcha.background.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.DefaultBackground</param-value>
        </init-param>-->
        <init-param>
            <description>背景颜色渐变, 开始颜色</description>
            <param-name>kaptcha.background.clear.from</param-name>
            <param-value>green</param-value>
        </init-param>
        <init-param>
            <description>背景颜色渐变, 结束颜色</description>
            <param-name>kaptcha.background.clear.to</param-name>
            <param-value>white</param-value>
        </init-param>
<!--        <init-param>
            <description>文字渲染器</description>
            <param-name>kaptcha.word.impl</param-name>
            <param-value>com.google.code.kaptcha.text.impl.DefaultWordRenderer</param-value>
        </init-param>-->
<!--       <init-param>
            <description>图片样式: FishEyeGimpy鱼眼,WaterRipple水纹,ShadowGimpy阴影,默认水纹</description>
            <param-name>kaptcha.obscurificator.impl</param-name>
            <param-value>com.google.code.kaptcha.impl.ShadowGimpy</param-value>
        </init-param>-->
 <!--       <init-param>
            <description>session中存放验证码的key键</description>
            <param-name>kaptcha.session.key</param-name>
            <param-value>KAPTCHA_SESSION_KEY</param-value>
        </init-param>-->


    </servlet>

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

推荐阅读更多精彩内容