六、Session和Cookie

JavaWeb会话技术

HTTP通信协议的特点:

1.应答式的协议,只能是客户端先发送请求然后服务器作出响应。

2.明文传输,传输的数据是明文,没有做加密之类处理

3.简单快速。HTTP协议相对简单,所以传输较快。

4.无状态,HTTP通信,不会记录客户端的请求信息。默认通信完成,传输断开。

基于无状态这点,如果客户端和服务器需要进行二次会话,且可能需要之前会话的数据这样的需求场景。

所以,WEB技术中,提供了2种解决方案,这两种解决方案就被称之为会话技术。分别是:Session和Cookie。

1.如果一方需要之前沟通的记录,在生活中是怎么处理的?

方案一: 将数据存储起来,需要时进行查看。Session

方案二:重新将之前的记录发送一次。Cookie

2.WEB中的Session技术

WEB中的Session技术,是在服务器创建一个Session容器,可以将数据存储在这个容器,然后将查找到这个容器key,给客户端,那么每次客户端来请求服务器时,可以将这个key带给服务器,服务器就可以根据这个key,找到客户端寄存在服务器的Session(数据容器),然后从session中获取存储的数据。

例如: 在超市里,将物品进行寄存,有一个寄存的号码牌,需要时,可以根据号码牌,拿到寄存的物品。

注意:

1.session是在服务器的内存中,开辟了一存储空间,默认是有效时间是30分钟,若没有主动释放,则30分钟会释放内存。

2.session容器是一个map结构的容器,根据key查找对应的session,若key不对,那么session将找不到(找不到不代表它消失了)。一般关闭浏览器,或者使用新的浏览器,服务器会分配一个新的key给浏览器,此时就找不到之前的那个session了,但是之前的session是在内存中的。

3.客户端从存储session对应的key是使用cookie技术存储的,所以session技术也是依赖cookie技术。

2.1.session使用

session作为一个会话对象,其中可以存储多次请求需要共享的数据。例如:验证码,当前登录用户都可以存在session。所以首先要有session容器。

在调试时发现,当第一次访问jsp页面时,会有Cookie,且Cookie中存在JSESSIONID的值,但是访问servlet的时候没有,因为JSP默认会创建session对象(session是JSP的内置对象之一),但是session是不会主动创建session对象的。所以在servlet中使用session,首先要创建一个session对象,而session与客户端的请求关联的,因为session表示会话,会话包含多个请求,所以需要根据请求对象,找到关联的session对象。


session示例.png
session示例2.png

以上图片,浏览器中Cookie中JSESSIONID对应的值,与服务器中产生的sesion对象的ID值一致,说明服务器将自己创建的session对象的ID值给了浏览器。且使用的是Cookie。所以session是依赖Cookie,因为需要使用Cookie存储自己的唯一标识,便于浏览器找到对应的Session.

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
 * @ClassName: SessionController 
 * @Description: 演示session的API
 * @author: Mr.T
 * @date: 2020年2月14日 上午11:36:30
 */
public class SessionController extends HttpServlet {

    private static final long serialVersionUID = -6539113475281947079L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("service方法执行了");
        // getSession() : 返回与当前请求关联的session 如果没有则创建一个新的session
        // getSession(create) : 返回当前关联的session对象, 如果create 为true,当前session不存在时创建一个,为false则返回null
        //一般都是使用  getSession() 
        HttpSession session = req.getSession();
        System.out.println("session的ID:"+session.getId());
        //resp.getWriter().println("Hello Session");
        //session中核心方法
        //session 作为作用域  其核心作用是数据管理
        //setAttribute(name, value) :向session 作用域中存储数据
        //getAttribute(name) : 从session作用域中获取数据
        //getAttributeNames() : 从session作用域中获取所有存储数据的name值
        //session生命周期方法
        //setMaxInactiveInterval(long) : 设置session 有效时间  单位是秒  
        //如果设置为0  或者 负数,那么session 将永远不会失效  不建议  因为session占服务器内存
        // tomcat 服务器 默认是 30分钟
        //session.setMaxInactiveInterval(interval);
        //invalidate() : 是这个session不关联任何对象,即取消session和request的关联
        //这样当前request 就无法找到这个session
        //session.invalidate();
        
    }   
    
}

2.2session目前的不足

session是存储在服务器的内存中,所以session只支持单应用,而不支持负载形式的应用架构。

所以session只支持单应用的架构,只支持只有一台服务器的架构。

session的不足.png

2.3.使用session记录当前用户

一般在开发中,会将当前登录用户,存储在内存中,便于其他地方使用。而在web程序,会将当前的登录用户,存储在session中。然后,在其他页面或者servlet中,若要使用当前用户信息,则可以直接从session中获取,不必根据用户名和密码重新查询,只需要登录一次即可。

代码:

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.sxt.pojo.User;
/**
 * @ClassName: UserController 
 * @Description: 用户控制类
 * @author: Mr.T
 * @date: 2020年2月14日 下午2:40:11
 */
public class UserController extends HttpServlet {
    
    private static final long serialVersionUID = 7723086583204133716L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        String password = req.getParameter("password");
        //根据用户名和密码查询用户
        //假设  用户名和密码 值都是 admin 当做登录成功
        if("admin".equals(userName) && "admin".equals(password)) {
            //将用户信息存在session中
            User user = new User(1, "admin", "password","韩梅梅");
            //放入session  便于在当前会话中  任何页面或者servlet 都可以直接拿到当前登录用户信息
            req.getSession().setAttribute("user", user);
        }
        //去登录成功页面
        resp.sendRedirect("success.jsp");
    }       
}

package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.sxt.pojo.User;
/**
 * @ClassName: TestController 
 * @Description: 用于测试 可以从session中获取当前登录用户
 * @author: Mr.T
 * @date: 2020年2月14日 下午2:47:58
 */
public class TestController extends HttpServlet {

    private static final long serialVersionUID = -5123674255870472885L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        User user = (User) session.getAttribute("user");
        System.out.println("当前登录的用户是:"+user.getRealName());
    }
    

}

package com.sxt.pojo;

public class User {
    
    private Integer userId;
    
    private String userName;
    
    private String password;
    
    private String realName;
    
    
    public User() {}

    public User(Integer userId, String userName, String password, String realName) {
        super();
        this.userId = userId;
        this.userName = userName;
        this.password = password;
        this.realName = realName;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRealName() {
        return realName;
    }

    public void setRealName(String realName) {
        this.realName = realName;
    }
    
    
    

}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="user.do">
    <p>用户名:<input type="text" name="userName"  /></p>
    <p>用户名:<input type="password" name="password"  /></p>
    <input  type="submit" value="登录"/>
</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<!-- 从session 获取当前登录用户的真实姓名 -->
欢迎:${user.realName}
</body>
</html>

2.4.使用session存储验证码

一般在web网页上看到的图片,其实是服务器将图片数据使用字节流,输出给浏览器,然后浏览器拿到数据后,将数据解析成图片,渲染在页面。

那么,在页面上看到的验证码图片,其实就是服务器生成的一张图片,然后将图片使用字节流发送给了,浏览器。然后浏览器解析。并且,在处理登录请求的servlet时,拿到用户输入的验证码和之前产生的验证码要进行比对。

那么此时,就是在登录的servlet,要使用造验证码的servlet产生的数据,但是造验证码servlet程序已经执行完成了,内存已经释放了。之前造的验证码字符串已经消失了,无法进行比对。基于这样的情况,所以一般是将产生验证码的字符串,存储在session中,这样在登录请求的servlet中,也可以拿到之前产生的验证码,从而进行比对。

产生验证码

package com.sxt.controller;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @ClassName: CheckCodeController 
 * @Description: 产生验证码的servlet
 * @author: Mr.T
 * @date: 2020年2月14日 下午3:27:44
 */
public class CheckCodeController  extends HttpServlet {

    private static final long serialVersionUID = -1597171426922505140L;
    /**
     * 验证码池  
     */
    static String[] codes = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d"};
    
    
    /**
     * 验证码的本质 其实就是 一个有随机字符串的图片
     * 服务器,将图片转化为字节流输出给浏览器
     * 浏览器解析流数据,将图片渲染在页面
     */
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //要使用Java程序  造一个含有随机字符串的图片
        //1. 创建一个背景图  画布
        BufferedImage image =  new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB);
        //2. 获取一个跟画布关联的画笔
        Graphics graphics = image.getGraphics();
        //3.使用画笔绘制信息
        //为画笔设置颜色
        graphics.setColor(Color.WHITE);
        //绘制一个填充的矩形  将默认黑色的画布 涂成白色
        graphics.fillRect(0, 0, 200, 100);
        //1. 获取验证码字符串   4个字符长度的验证码
        String code = getCode(4);
        //将验证码 放入session 便于在其他地方使用
        req.getSession().setAttribute("code", code);
        // 设置画笔的字体 宋体 加粗 倾斜 35磅值
        Font font = new Font("宋体", Font.BOLD | Font.ITALIC, 60);
        graphics.setFont(font);
        //2.根据循环将字符 绘制到图片上
        for (int i = 0; i < code.length(); i++) {
            //随机改变画笔颜色
            Color c = getColor();
            graphics.setColor(c);
            //获取具体的字符
            String str = code.charAt(i)+"";
            //让文字的横坐标值变大,从而向右侧移动
            int x = 20 + i*40;
            graphics.drawString(str, x,65);
        }
        
        
        
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
    
    
    /**
     * @Title: getColor
     * @author: Mr.T   
     * @date: 2020年2月14日 下午3:54:56 
     * @Description: 随机产生颜色
     * @return
     * @return: Color
     */
    private Color getColor() {
        //因为RGB颜色 是由  0-255,0-255,0-255 的数值组成
        Random random = new Random();
        int r = random.nextInt(255);
        int g = random.nextInt(255);
        int b = random.nextInt(255);
        return new Color(r, g, b);
    }
    /**
     * @Title: getCode
     * @author: Mr.T   
     * @date: 2020年2月14日 下午3:57:55 
     * @Description: 产生随机字符串
     * @param count 验证码的个数
     * @return
     * @return: String
     */
    private String getCode(int count) {
        String code = "";
        Random random = new Random();
        for (int i = 0; i < count; i++) {
            int index = random.nextInt(codes.length);
            code = code + codes[index];
        }
        return code;
    }
    
    /**
     * @Title: method
     * @author: Mr.T   
     * @date: 2020年2月14日 下午4:03:38 
     * @Description: 绘制验证码相关API的演示
     * @return: void
     */
    private void method(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 要使用Java程序 造一个含有随机字符串的图片
        // 1. 创建一个背景图 画布
        BufferedImage image = new BufferedImage(200, 100, BufferedImage.TYPE_INT_RGB);
        // 2. 获取一个跟画布关联的画笔
        Graphics graphics = image.getGraphics();
        // 3.使用画笔绘制信息
        // 为画笔设置颜色
        graphics.setColor(Color.WHITE);
        // 绘制一个填充的矩形 将默认黑色的画布 涂成白色
        graphics.fillRect(0, 0, 200, 100);
        // 可以在白色画布上绘制文字 注意 此时画笔是白色 绘制信息也是白色 所以需要改变画笔的颜色
        // 画笔设置为红色
        graphics.setColor(Color.RED);
        // 设置画笔的字体 宋体 加粗 倾斜 35磅值
        Font font = new Font("宋体", Font.BOLD | Font.ITALIC, 30);
        graphics.setFont(font);
        graphics.drawString("情人节快乐", 10, 55);
        // 绘制干扰线 2点 连起来 就是一条线
        graphics.drawLine(0, 0, 200, 100);
        // 使用输出流 将图片数据输出给浏览器
        ImageIO.write(image, "jpg", resp.getOutputStream());
    }
    
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="user.do">
    <p>用户名:<input type="text" name="userName"  /></p>
    <p>用户名:<input type="password" name="password"  /></p>
    <p>用户名:<input type="password" name="checkCode" style="width: 50px"  />
        <img onclick="refreshCode()" src="checkCode.do" style="height: 50px" id="checkCodeImg" />
    </p>
    <input  type="submit" value="登录"/>
</form>
</body>
<script type="text/javascript">
    //刷新验证码
    function refreshCode(){
        console.log("点击了");
        //设置 src的值  值一旦发生改变  浏览器 会重新请求这个url地址
        //浏览器存在缓存策略,当src 后面值一样,浏览器是不会重新请求
        //那么servlet就不会产生新的验证码  所以验证码没有发生改变
        //基于这样的情况  一般会在src 后面的url 拼接一个不可重复的字符 ,一般使用随机数 或者 时间戳
        document.getElementById("checkCodeImg").src = "checkCode.do?"+new Date();
    }
</script>
</html>

使用Hutool生成验证码:

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        /**
         *  width  : 图片的宽度
         *  height : 图片高度
         * codeCount : 验证码的个数
         * circleCount : 干扰元素个数
         */
        LineCaptcha checkObj = CaptchaUtil.createLineCaptcha(200, 100, 4, 100);
        //获取具体的验证码字符串
        String code = checkObj.getCode();
        //将生成的验证码 放入session
        req.getSession().setAttribute("code", code);
        //将验证码输出到页面
        checkObj.write(resp.getOutputStream());
    }

校验验证码:

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户输入的验证码
        String checkCode = req.getParameter("checkCode");
        //从session中获取产生时存储的验证码
        Object code = req.getSession().getAttribute("code") ;
        //对验证码进行对比
        if(checkCode == null || !checkCode.equals(code.toString())) {
            System.out.println("验证码错误!");
            resp.sendRedirect("login.jsp");
            return;
        }
        String userName = req.getParameter("userName");
        String password = req.getParameter("password");
        //根据用户名和密码查询用户
        //假设  用户名和密码 值都是 admin 当做登录成功
        if("admin".equals(userName) && "admin".equals(password)) {
            //将用户信息存在session中
            User user = new User(1, "admin", "password","韩梅梅");
            //放入session  便于在当前会话中  任何页面或者servlet 都可以直接拿到当前登录用户信息
            req.getSession().setAttribute("user", user);
        }
        //去登录成功页面
        resp.sendRedirect("success.jsp");
    }

3.WEB中的Cookie技术

在WEB中,Cookie技术是将需要的数据,由服务器写入(响应)到浏览器中(内存中,一个文件中),然后,浏览器接下来的请求,都会将这些数据通过请求头,带给服务器。服务器可以通过解析请求头,从而解析这些数据。这种技术方案就被称之为Cookie.

注意:

  1. Cookie的存储2种方式,一种是内存中一种磁盘文件中,这两种方式是Cookie生命周期的体现。默认Cookie的生命周期,是在内存中,基本是一次会话。
  2. Cookie是由服务器,通过响应对象,将数据通知给客户端,让客户端在本地进行一定的存储,且下次来请求带过来。

3.1.Cookie的使用

  1. 创建Cookie

    Cookie cookie1 = new Cookie("name","value"); // cookie是map结构

  2. 通过response对象,将创建的cookie给浏览器

    resp.addCookie(cookie1); //通过响应对象,设置set-cookie的响应头,浏览器拿到这个响应头后 ,会将响应头找中的数据保存到浏览器的内存中或者本地

  3. 以后的请求,浏览器会将cookie信息带给服务器,服务器可以从请求头中,解析cookie信息。

代码示例:

/**
 * @ClassName: CookieController 
 * @Description: 用于演示Cookie相关的API
 * @author: Mr.T
 * @date: 2020年2月16日 上午10:47:39
 */
public class CookieController extends HttpServlet {

    private static final long serialVersionUID = 2285648241402004645L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //cookie是由服务器  告诉客户端 要存储哪些数据 
        //cookie是由服务器创建  然后 服务器将这个cookie 给客户端   客户端将cookie数据进行存储
        //之后的请求,都会将cookie数据带给服务器
        //1. 创建Cookie --- cookie数据结构  map接口
        Cookie cookie1 = new Cookie("cookieName", "cookieValue");
        //设置cookie的有效期 单位是秒   如果设置为 0 则表示要删除这个cookie
        //如果设置了有效期,浏览器会将cookie存储在自己本地的文件中,如果不清除,且没有过有效期,那么cookie就有效
        //之后请求,会将数据带给服务器
        cookie1.setMaxAge(60*2);//2分钟
        //设置cookie是否允许浏览器进行操作   由于cookie是存在浏览器中,浏览器可以通过js对cookie进行数据操作
        //servlet 3.0 后   setHttpOnly(true) : 只有HTTP可以操作Cookie 浏览器无法操作Cookie
        cookie1.setHttpOnly(true);
        //注意,cookie 默认只对当前项目生效   有效路径  当前项目   域名  项目名
        //但是实际中,存在子域名,当需要多个子域名cookie也生效,则需要设置这个属性 
        //cookie1.setDomain(pattern);
        //注意,默认只对项目及项目的子目录生效。限制生效的URI,通过setPath进行设置 
        //cookie1.setPath(uri);
        
        //2. 通过响应对象  将cookie 给客户端
        resp.addCookie(cookie1);
        resp.getWriter().print("Hello  Cookie");
    }
}
@Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //cookie数据 是浏览器 通过请求头的信息  将数据传给服务器的,所以解析cookie 要从请求对象中解析
        // 获取所有的cookie
        Cookie[] cookies = req.getCookies();
        //判断cookie是否存在
        if(cookies != null) {
            //只能通过遍历的方式进行判断   遍历所有cookie 获取每个cookie的name值   对比name 从而拿到自己需要的cookie对象
            for (Cookie cookie : cookies) {
                //获取cookie的name
                String name = cookie.getName();
                //获取cookie的Value值
                String value = cookie.getValue();
                if(name.equals("cookieName")) {
                    System.out.println("cookieName 对应的值:"+value);
                }
            }
        }
    }

cookie01.png
cookie02.png

3.2.Cookie的不足

Cookie是将数据存储在浏览器,然后每次浏览器自动会将Cookie数据放在请求头中,传递给无服务器。

1.安全性相对较差,可以在传输的过程中,修改Cookie中数据。

2.无法与其它终端共享数据。例如:用户在PC端进行了操作,数据存在Cookie中,用户在移动端是看不到用户在PC端的操作的。

3.Cookie中存储的数据有限.

3.3.Cookie的场景

1.早期时,使用Cookie做购物车。将用户的购买的商品放入Cookie中。但是在现在,使用Cookie作为购物车,无法满足需求,因为没有办法在其它终端共享数据。所以,为了共享数据,会将数据存在服务器数据库中,便于在任何平台都能看到用户的购物车,前提是用户登录了。所以,如果用户没有登陆,会将用户购物车数据存储在Cookie中,但是,当用户登录后,将Cookie中的数据保存到数据库中。

2.用户的浏览记录。一般会将用户的浏览记录放入Cookie。例如: 浏览器的访问记录.

3.使用Cookie记录用户的登录凭证,让用户免密登录。记住密码。

3.5.使用Cookie记住密码

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<!-- 用户登录表单 -->
<form action="user.do" method="post">
    <!-- 从cookie中 获取 对应的值 -->
    <p>用户名<input type="text" name="userName" value="${cookie.userName.value}" /></p>
    <p>密码:<input type="text" name="password" value="${cookie.password.value}" /></p>
    <p>记住密码:<input type="checkbox" name="remeber"  value="1"/></p>
    <p><input type="submit" value="登录" /></p>
</form>
</body>
</html>
package com.sxt.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * @ClassName: UserController 
 * @Description: @WebServlet 就是代替 web.xml中的servlet 配置
 *              "/user.do"  就是xml中 url-pattern的值
 * @author: Mr.T
 * @date: 2020年2月16日 下午2:34:42
 */
@WebServlet("/user.do")
public class UserController extends HttpServlet {

    /**
     * @fieldName: serialVersionUID
     * @fieldType: long
     * @Description: TODO
     */
    private static final long serialVersionUID = 7723086583204133716L;

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户名
        String userName = req.getParameter("userName");
        //获取密码
        String password = req.getParameter("password");
        //是否记住密码
        String remeber = req.getParameter("remeber");
        /**
         * 如果记住密码  可以将账号密码信息放入cookie  下次登录 直接从cookie中取  不用再输入账号面
         * 
         */
        if("1".equals(remeber)) {//表示记住密码
            //将账号放入cookie
            Cookie userNameCookie = new Cookie("userName", userName);
            //由于 cookie 默认是浏览器关闭就会消失,设置cookie的有效期
            userNameCookie.setMaxAge(60*60*24*7);//1个星期
            //通过resp 将cookie给浏览器
            resp.addCookie(userNameCookie);
            
            //将密码 放入cookie
            Cookie passwordCookie = new Cookie("password", password);
            //由于 cookie 默认是浏览器关闭就会消失,设置cookie的有效期
            passwordCookie.setMaxAge(60*60*24*7);//1个星期
            //通过resp 将cookie给浏览器
            resp.addCookie(passwordCookie);
        }
        resp.getWriter().print("登录成功"); 
    }
}

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

推荐阅读更多精彩内容

  • Session 在Web开发中,服务器可以为每个用户浏览器创建一个会话对象(Session对象),注意:一个浏览器...
    简单一点点阅读 327评论 0 0
  • 背景在HTTP协议的定义中,采用了一种机制来记录客户端和服务器端交互的信息,这种机制被称为cookie,cooki...
    时芥蓝阅读 2,361评论 1 17
  • 今天遇到简书,顺便开始尽量每天写一点东西,希望这是一个能长下去的写文字的地方
    烟渺城阅读 116评论 0 1
  • 陈雄焕 浙人医天台分院 创伤中心 医师 党员 “手机上不断推送着湖北的疫情消息,虽然有了政府以及来自四面八方的医疗...
    c33da8c0aee2阅读 124评论 0 0
  • 今天,我的简书文章有100篇,值得庆贺,我坚持了52天。 原本写文章就是觉得不能做到日更。更没法做到天天坚持,但有...
    心灵舞者116阅读 75评论 0 0