Servlet

key point

  • Servlet GenericServlet HttpServlet HttpRequestServlet HttpResponseServlet
  • 保持状态的方法
  • Servlet 之间的消息共享级别
  • Context Listener(application)
    • ServletContextListener
    • ServletContextAttributeListener
  • Session Listener session
    • HttpSessionListener
    • HttpSessionAttributeListener
    • HttpSessionActivationListener
    • HttpSessionBindingListener
  • Filter

Java 和PHP体系对比

体系 负载均衡 中间件 框架 数据库
JAVA nginx tomcat/jboss spring/play mysql/postgre...
PHP nginx php-cgi thinkphp/laravel mysql/postgre...

基本信息

servlet 的全称是 Server Applet。 是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态内容。servlet不仅能处理http协议还能处理ftp等协议。
在servlet3.0之前一个servlet应用由一系列处理请求的Java编译文件(*.class)和一个告诉Java编译文件是怎么组织的部署描述符(web.xml)构成。
在3.0之后 部署描述可以通过Java编码的方式进行,web.xml可以省略。

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Copyright 2004 The Apache Software Foundation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package javax.servlet;

import java.io.IOException;


/**
 * Defines methods that all servlets must implement.
 *
 * <p>A servlet is a small Java program that runs within a Web server.
 * Servlets receive and respond to requests from Web clients,
 * usually across HTTP, the HyperText Transfer Protocol. 
 *
 * <p>To implement this interface, you can write a generic servlet
 * that extends
 * <code>javax.servlet.GenericServlet</code> or an HTTP servlet that
 * extends <code>javax.servlet.http.HttpServlet</code>.
 *
 * <p>This interface defines methods to initialize a servlet,
 * to service requests, and to remove a servlet from the server.
 * These are known as life-cycle methods and are called in the
 * following sequence:
 * <ol>
 * <li>The servlet is constructed, then initialized with the <code>init</code> method.
 * <li>Any calls from clients to the <code>service</code> method are handled.
 * <li>The servlet is taken out of service, then destroyed with the 
 * <code>destroy</code> method, then garbage collected and finalized.
 * </ol>
 *
 * <p>In addition to the life-cycle methods, this interface
 * provides the <code>getServletConfig</code> method, which the servlet 
 * can use to get any startup information, and the <code>getServletInfo</code>
 * method, which allows the servlet to return basic information about itself,
 * such as author, version, and copyright.
 *
 * @author  Various
 *
 * @see     GenericServlet
 * @see     javax.servlet.http.HttpServlet
 *
 */


public interface Servlet {

    /**
     * Called by the servlet container to indicate to a servlet that the 
     * servlet is being placed into service.
     *
     * <p>The servlet container calls the <code>init</code>
     * method exactly once after instantiating the servlet.
     * The <code>init</code> method must complete successfully
     * before the servlet can receive any requests.
     *
     * <p>The servlet container cannot place the servlet into service
     * if the <code>init</code> method
     * <ol>
     * <li>Throws a <code>ServletException</code>
     * <li>Does not return within a time period defined by the Web server
     * </ol>
     *
     *
     * @param config            a <code>ServletConfig</code> object 
     *                  containing the servlet's
     *                  configuration and initialization parameters
     *
     * @exception ServletException  if an exception has occurred that
     *                  interferes with the servlet's normal
     *                  operation
     *
     * @see                 UnavailableException
     * @see                 #getServletConfig
     *
     */

    public void init(ServletConfig config) throws ServletException;
    
    

    /**
     *
     * Returns a {@link ServletConfig} object, which contains
     * initialization and startup parameters for this servlet.
     * The <code>ServletConfig</code> object returned is the one 
     * passed to the <code>init</code> method. 
     *
     * <p>Implementations of this interface are responsible for storing the 
     * <code>ServletConfig</code> object so that this 
     * method can return it. The {@link GenericServlet}
     * class, which implements this interface, already does this.
     *
     * @return      the <code>ServletConfig</code> object
     *          that initializes this servlet
     *
     * @see         #init
     *
     */

    public ServletConfig getServletConfig();
    
    

    /**
     * Called by the servlet container to allow the servlet to respond to 
     * a request.
     *
     * <p>This method is only called after the servlet's <code>init()</code>
     * method has completed successfully.
     * 
     * <p>  The status code of the response always should be set for a servlet 
     * that throws or sends an error.
     *
     * 
     * <p>Servlets typically run inside multithreaded servlet containers
     * that can handle multiple requests concurrently. Developers must 
     * be aware to synchronize access to any shared resources such as files,
     * network connections, and as well as the servlet's class and instance 
     * variables. 
     * More information on multithreaded programming in Java is available in 
     * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
     * the Java tutorial on multi-threaded programming</a>.
     *
     *
     * @param req   the <code>ServletRequest</code> object that contains
     *          the client's request
     *
     * @param res   the <code>ServletResponse</code> object that contains
     *          the servlet's response
     *
     * @exception ServletException  if an exception occurs that interferes
     *                  with the servlet's normal operation 
     *
     * @exception IOException       if an input or output exception occurs
     *
     */

    public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;
    
    

    /**
     * Returns information about the servlet, such
     * as author, version, and copyright.
     * 
     * <p>The string that this method returns should
     * be plain text and not markup of any kind (such as HTML, XML,
     * etc.).
     *
     * @return      a <code>String</code> containing servlet information
     *
     */

    public String getServletInfo();
    
    

    /**
     *
     * Called by the servlet container to indicate to a servlet that the
     * servlet is being taken out of service.  This method is
     * only called once all threads within the servlet's
     * <code>service</code> method have exited or after a timeout
     * period has passed. After the servlet container calls this 
     * method, it will not call the <code>service</code> method again
     * on this servlet.
     *
     * <p>This method gives the servlet an opportunity 
     * to clean up any resources that are being held (for example, memory,
     * file handles, threads) and make sure that any persistent state is
     * synchronized with the servlet's current state in memory.
     *
     */

    public void destroy();
}

public void init(ServletConfig servletConfig) throws ServletException ;

init 方法在整个类的生命周期内只执行一次(不是每一次用户请求一次、这个类就会被生成一次,而是当用户第一次请求这个类的时候这个类会被生成,然后这个类会放在JVM的heap里面,直到被GC)

ServletConfig servletConf

容器从部署文件中读出Servlet初始化参数,并把这些参数交给ServletConfig,然后把ServletConfig传递给servlet的init(ServletConfig config)方法。从而避免了在类里硬编码

URI和servlet对应的这个部分可以用注解来代替

@WebServlet(name = "test", urlPatterns = {"/test1/test2/test3/"})
@WebInitParam(name = "color", value = "red")
public class MyServlet2 extends HttpServlet{
     @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException{
        PrintWriter printWriter = response.getWriter();
        printWriter.printf(getServletConfig().getInitParameter("color"));
    }
}

对于之前的servlet接口有两个可以改进的地方

  • 对于我们没有功能的方法也要进行实现
  • servletConfig要我们自己去定义
    于是就有了
    GenericServlet 这个类里面有ServletConfig属性,实现了servlet接口,我们的类继承GenericServlet这个接口,只用对有必要的函数进行重写。

为了便于http的处理,JEE提供了HttpServlet。HttpServlet继承于GenericServlet。

在实现Servlet接口的service方法的时候将入参向下转型为HttpServletRequest 和HttpServletRequest。这样我们可以使用HTTP协议的一些特性。
HttpServletRequest

  • String getContextPath();//返回context(上下文的根)的路径
  • Cookie[] getCookies();//获得cookie
  • String getHeader(String name);//根据HTTP头的key获得value
  • String getMethod();//获得请求的方法
  • String getQueryString(); //返回URI?后面的全部部分
  • HttpSession getSession();//找到和这个请求的有关的session。如果没有找到,创建新的session。

HttpServletResponse

  • addCookie(Cookie cookie);
  • addHeader();
  • sendRedirect(); 向浏览器response 状态码为302 location为sendRedirect里的地址
    HttpService 重载service方法 根据HttpRequest.method 的不同将请求分发到不同的函数中,后续继承HttpService的类只要重写要进行处理的Http方法的方法就好。比如我要处理http的get,我继承于HttpService的类只要重写doGet方法就好。

Servlet保持状态的4种方法

  1. 网址重写 ?a=b&c=d
  2. form-data
  3. cookie
  4. HttpSession
    第1种和第2种方法可以通过request.getParameter("")的方式 通过key来访问值
    第3种 cookie是放在http头部中的 每一次向服务器发送信息的时候都会包括该域名下所有的cookie,cookie的个数是有限制的最大数量为20个。通过HttpServletReuest 的getCookies()方法可以获得所有的cookie 然后通过比较cookie名称和我们预想的cookie的name是否一致得到我们想要的cookie。
    第4种方法 一般向服务器发送消息的时候会有一个叫做JESSIONID Cookie 里面包含了在内存这次访问session的key,服务器可以根据这个key反序列化出相关的信息。在Servlet中可以通过HttpServlet的getSession() 方法得到本次访问的HttpSession 对象。

Servlet之间的消息共享

Servlet 之间通过Attribute(属性)的方式进行消息共享。消息分享的层级有以下三个

  • request(当个访问者当次请求)
  • session (当个访问者,所有的请求)
  • application (全部访问者,所有的请求)

在request 级别的attirbute 的使用方法一般是

Map<String, String[]> bigCities = new HashLinkedMap<>();
bigCities.put("China",{"Beijing", "Shanghai", "Hongkong"});
bigCities.put("USA",{"New York", "Boston", "Washington, D.C."})
request.setAttrribuate("bigCities",bigCities);
RequestDispatcher rd = request.getRequestDispatcher("/show.jsp");
rd.forward(request, response);

将属性放到request中,把这个属性转交给jsp页面进行页面的渲染

<c:forEach item = "${requestScope.bigCities}" var = "country">
    ${country.key}
    <c:forEach item= "${country.value}" var ="city" varStatus = "status">
        ${city}
        <c:if test = "${! status.last}">
            <br/>
        </c:if>
    </c:forEach>
</c:forEach>

监听器

进行事件驱动编程,当什么事情发生的时候我们要做出合适的反应
定义监听器有两个方法

@WebListener
public class ListenerClass implements ListenerInterface{
}

或者

<listen>
    <listener-class>org.cor.projectName.something</listener-class>
</listen>

Context Listener 上下文级别的监听器

ServletContextLister

当一个application的context被容器所创建的时候,容器会调用实现这个接口的对象的特定方法

  • void contextInitialized(ServletContextEvent event);
    对环境的初始化做出响应
  • void contextDestoryed(ServletContextEvent event);
    对环境的析构做出响应
  • ServletContext getServletContext();
    得到上下文对象
    for example
@WebListener
public class AppContextListener implements ServletContextListener{
    @Override
    public void contextInitialized(ServletContextEvent event){
        Map<String, String> contries = new HashMap<String, String>();
        contries.put("ca", "Canada");
        contries.put("us", "USA");
    }
}

当一个application的context被容器所创建的时候,我们给容器增加一个Attribute

ServletContextAttributeListener

当application范围内的attribute发生改变的时候,容器会调用实现这个接口的对象的特定方法

  • void attributeAdded(ServletContextAttributeEvent event);
    增加属性
  • void attributeRemoved(ServletContextAttributeEvent event);
    删除属性
  • void attributeReplaced(ServletContextAttributeEvent event);
    替换属性的内容

Session Listener session级别的监听器

HttpSessionListener

这个接口的作用是和上面的ServletContextLister相类似只不过是作用于session范围

  • sessionCreated(HttpSessionEvent event);
    当一个session被创建时会调用这个方法
  • sessionDestroyed(HttpSessionEvent event);
    当一个session被销毁时调用这个方法
  • HttpSession getSession();
    获得要被操作的session

HttpSessionAttributeListener

这个接口的作用和上面的ServletContextAttributeListener 相类似,作用于session范围

  • void attributeAdded(HttpSessionBindingEvent event)
    属性添加
  • void attributedRemoved(HttpSessionBindingEvent event);
    属性删除
  • void attributeReplace(HttpSessionBindingEvent event);

HttpSessionActivationListener

session 是保存在内存中,当内存不够的时候容器会尝试着将session进行迁移或者序列化,通过这个接口能对做出容器的行为做出反应

  • void sessionDidActivate(HttpSessionEvent event);(容器尝试将session触发)
  • void sessionWillPassivate(HttpSessionEvent event);(容器尝试着将session钝化)

HttpSessionBindingListener

如果一个类想知道什么时候被绑定到HttpSesison上,那么这个类要实现HttpSessionBindingListener接口,在绑定的时候或者不绑定的时候,这个类会做出合适反应

public BigCity implements HttpSessionBindingListener{
    ...
    @Override
    public void valueBound(HttpSessionBindingEvent event){
    }
    @Override
    public void valueUnbound(HttpSessionBindingEvent event){
    }
}

在把这个类的对象放到session的setAttribute的时候,valueBound会被调用。

过滤器

过滤器是指请求过来的时候先拦截请求,处理一波之后在交给servlet,在验证登陆状态字符处理等的方面都有应用。
定义过滤器有两个方法

@WebFilter(filterName = "***Filter", urlPatterns = {"/*"})
//过滤器必须要以Filter结尾
public class ***Filter implements Filter{
}

或者在部署文件中

<filter>
    <filter-name>***Filter</filter-name>
    <filter-class>test.andrew.io.***Filter</filter-class>
</filter>
<filter-mapping>
    <filter-name>***Filter</filter-name>
    <url-patten>/*</url-patten>
</filter-mapping>

一个典型的Filter的应用,设置字符

public class UTF8Filter implements Filter{

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain fchain) throws IOException, ServletException {
        // TODO Auto-generated method stub
        //System.out.println("先执行过滤器里面的内容。。。。。");
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

       fchain.doFilter(request, response);
        
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO Auto-generated method stub
               
    }
}

Spring MVC

就和其他的框架一样 Sring 的出现也是为了简化开发

  1. Spring 环境的构建
    1.1 old school
    step1: 在web.xml 指定把所有的请求都发送给处理
    <?xml version="1.0" encoding="UTF-8"?>
                        <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>app</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>app</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    </web-app>
    
  • contextLoaderListener
    ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。至于ApplicationContext.xml这个配置文件部署在哪,如何配置多个xml文件,书上都没怎么详细说明。现在的方法就是查看它的API文档。在ContextLoaderListener中关联了ContextLoader这个类,所以整个加载配置过程由ContextLoader来完成。看看它的API说明
    • 第一段
      ContextLoaderServlet的API,可以看到它继承了ContextLoader这个类而且它实现了ServletContextListener。
      主要的实现是基于ContextLoader 这个类.
    • 第二段
      ContextLoader创建的是 XmlWebApplicationContext这样一个类,它实现的接口是WebApplicationContext->ConfigurableWebApplicationContext->ApplicationContext->
      BeanFactory这样一来spring中的所有bean都由这个类来创建
    • 第三段
      讲如何部署applicationContext的xml文件,如果在web.xml中不写任何参数配置信息,默认的路径是"/WEB-INF/applicationContext.xml,在WEB-INF目录下创建的xml文件的名称必须是applicationContext.xml。如果是要自定义文件名可以在web.xml里加入contextConfigLocation这个context参数:
      <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      /WEB-INF/classes/applicationContext-.xml
      </param-value>
      </context-param>
      <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
      /WEB-INF/classes/applicationContext-
      .xml
      </param-value>
      </context-param>
      在<param-value> </param-value>里指定相应的xml文件名,如果有多个xml文件,可以写在一起并一“,”号分隔。上面的applicationContext-.xml采用通配符,比如这那个目录下有applicationContext-ibatis-base.xml,applicationContext-action.xml,applicationContext-ibatis-dao.xml等文件,都会一同被载入。
      由此可见applicationContext.xml的文件位置就可以有两种默认实现:
      第一种:直接将之放到/WEB-INF下
      第二种:将之放到classpath下,但是此时要在web.xml中加入<context-param>,用它来指明你的applicationContext.xml的位置以供web容器来加载。按照Struts2 整合spring的官方给出的档案,写成:
      <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/applicationContext-
      .xml,classpath:applicationContext-.xml</param-value>
      </context-param>

但是也不一定要定义applicationContext.xml, 如果不定义 applicationContext

1.2 使用config方bo

  1. Spring对请求的处理
  2. Spring 的ORM
  3. Spring的不同环境

spring part

该注解用于读取Request请求的body部分数据
资料1
资料2
资料3

Spring 环境的构建

每种语言采用自动化构建的方式不尽相同,Python用的是pip,PHP用的是Composer,现在Java社区比较常用的是gradle和maven。
下面介绍maven的依赖构建
首先用ide构建一个maven的项目

一个pom.xml的样例

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>andrew.io</groupId><!--组织名称-->
    <artifactId>spring</artifactId><!--项目名称-->
    <version>1.0-SNAPSHOT</version><!--版本名称-->

    <dependencies>
        <!--在这个位置添加依赖的包-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.10.5.RELEASE</version>
        </dependency>
    </dependencies>
</project>

一个简易的Spring MVC的分层

和其他语言的项目一样,一个简单的spring mvc project也会对项目进行分层。分的层次大致如下

  1. controller
    主要用来组装客户端发过来的信息然后给业务层进行处理
    捕捉异常,对异常进行合适处理
    将结果反馈给请求方
  2. service
    负责主要的业务逻辑的操作
  3. dao
    数据库CRUD
  4. domian
    对象和数据库中的实体对应
  5. config spring
    配置类和spring配置文件(xml,yum,property)

这样可以明确每个层次的边界、减少每个层次之间的耦合度、增强复用性。

通过Spring MVC响应一个请求

当一个请求被容器响应的时候,首先由spring框架的DispatcherServlet进行处理。它是一个前端控制器,在Spring框架中通过单例模式实现,所有的请求都会通过它将任务派发被Controller。典型的应用程序中会有多个控制器,DispatcherServlet会查询一个或者多个控制器映射(handler mapping)来确定要派发给谁。Controller的职责主要是将发过来的request做一个合适的处理(网址重写?a=b,还是通过表单提交(form-data)的post中的数据,或者是application-* 形式的),在把数据发送给server层,server层根据业务的要求对数据进行加工,在加工过程的CRUD由Dao层负责,之后将处理好的结果返回给Contorller。Controller将得到的数据进行打包,并且标示出用于渲染输出的视图名,同时将这些数据返回给DispatcherServlet。DispatcherServlet会将使用视图解析器(view resolver)来将逻辑视图名匹配为一个特定的视图实现。视图将使用模型数据渲染输出。由此一次请求完成。

配置DispatcherServlet

配置可以通过web.xml 实现,但是xml毕竟不如代码清晰,现在比较推荐通过java类进行配置以下为一个配置类

public class WebAppInitializer
        extends AbstractAnnotationConfigDispatcherServletInitializer{
    //
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[0];
    }
    //配置文件类
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[0];
    }
    //指定上下文的根
    protected String[] getServletMappings() {
        return new String["/"];
    }
}

怎么发挥作用的?

st=>start: 开始
servlet=>operation: 容器查找实现 ServletContainerInitializer接口的类
spring=>operation: spring提供了这个接口的实现,但是它会找实现了WebApplicationInitailizer的类
spring3=>operation:  spring3.2提供了一个WebApplicationInitailizer的基础实现
,叫做AbstractAnnotationConfigDispatcherServletInitializer,
但是正如名字显示的是Abstract(抽象的)需要通过开发者进行实现
e=>end: 结束
st->servlet->spring->spring3->e
st=>start: 开始

e=>end: 结束

Spring Boot 简化开发

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

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,644评论 18 139
  • 一 servlet概述 狭义的Servlet指javax.servlet包中的一个接口,而广义的Servlet则是...
    静慎独阅读 454评论 0 0
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,222评论 11 349
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,605评论 18 399
  • Servlet:Sun公司制订的一种用来扩展Web服务器功能的组件规范。当浏览器将请求发送给Web服务器(比如:a...
    南山伐木阅读 583评论 0 4