Springboot自定义xml文件解析

有时候,要通过自定义XML配置文件来实现一些特定的功能。这里通过例子来说明。

1、说明

首先,看部分spring加载bean文件的源码:
spring-beans-5.0.6.RELEASE.jar!/org/springframework/beans/factory/xml/PluggableSchemaResolver.class

public class PluggableSchemaResolver implements EntityResolver {  
    public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";  
    private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class);

spring-beans-5.0.6.RELEASE.jar!/org/springframework/beans/factory/xml/DefaultNamespaceHandlerResolver.class

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {  
    public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";  
    protected final Log logger;  
    @Nullable

可以看出,spring在加载xml文件的时候,会默认读取配置文件META-INF/spring.schemasMETA-INF/spring.handlers。这样,我们就可以在这两个文件添加我们自定义的xml文件格式和xml文件解析处理器。

2、解析自定义xml配置文件

2.1 创建一个基本的Springboot工程

新建一个Springboot工程,pom如下。
SelfDefineXmlTrial/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>com.lfqy.springboot</groupId>
    <artifactId>SelfDefineXmlTrial</artifactId>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    </dependencies>

</project>

然后,新建一个用于测试controller。
com.lfqy.springboot.selfdefxml.controller.SelfDefXmlController

package com.lfqy.springboot.selfdefxml.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Created by chengxia on 2022/5/7.
 */

@RestController
@RequestMapping("/selfdefxml")
public class SelfDefXmlController {
    @RequestMapping("/hello")
    public String hello(){
        return "Hello world!";
    }
}

最后,创建一个Springboot的启动类。
com.lfqy.springboot.selfdefxml.SelfDefXmlApplication

package com.lfqy.springboot.selfdefxml;

import com.lfqy.springboot.selfdefxml.beans.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@SpringBootApplication
public class SelfDefXmlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SelfDefXmlApplication.class);
        System.out.println("The application has been started ....");
    }
}

运行启动之后,浏览器访问http://localhost:8080/selfdefxml/hello效果如下:

image.png

2.2 添加自定义的xml并解析

2.2.1 添加自定义xml格式说明和处理器配置

修改前面提到的配置文件META-INF/spring.schemasMETA-INF/spring.handlers,添加xml格式说明。
META-INF/spring.schemas

http\://www.mmpp.com/schema/selfdef.xsd=META-INF/selfdef.xsd

META-INF/spring.handlers

http\://www.mmpp.com/schema/selfdef=com.lfqy.springboot.selfdefxml.selxmlparse.UserNamespaceHandler

添加xml格式说明配置文件。
META-INF/selfdef.xsd

<?xml version="1.0" encoding="UTF-8" standalone="no"?>  
  
<schema xmlns="http://www.w3.org/2001/XMLSchema"  
        xmlns:tns="http://www.mmpp.com/schema/selfdef"  
        targetNamespace="http://www.mmpp.com/schema/selfdef"  
        elementFormDefault="qualified">  
    <element name="user">  
        <complexType>            <attribute name="id" type="string"/>  
            <attribute name="name" type="string"/>  
            <attribute name="address" type="string"/>  
        </complexType>    </element>  
</schema>

2.2.2 添加自定义xml格式处理器

添加自定义xml格式处理器类。
com.lfqy.springboot.selfdefxml.selxmlparse.UserNamespaceHandler

package com.lfqy.springboot.selfdefxml.selxmlparse;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * Created by chengxia on 2022/7/3.
 */
public class UserNamespaceHandler extends NamespaceHandlerSupport {

    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

新增xml格式解析类。
com.lfqy.springboot.selfdefxml.selxmlparse.UserBeanDefinitionParser

package com.lfqy.springboot.selfdefxml.selxmlparse;

import com.lfqy.springboot.selfdefxml.beans.User;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

/**
 * Created by chengxia on 2022/7/3.
 */
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

    @Override
    protected Class<?> getBeanClass(Element element) {
        return User.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String name = element.getAttribute("name");
        String address = element.getAttribute("address");

        if (StringUtils.hasText(name)) {
            builder.addPropertyValue("name", name);
        }
        if (StringUtils.hasText(address)) {
            builder.addPropertyValue("address", address);
        }
    }
}

2.2.3 添加自定义的bean类

新增自定义xml对应的bean类。
com.lfqy.springboot.selfdefxml.beans.User

package com.lfqy.springboot.selfdefxml.beans;

/**
 * Created by chengxia on 2022/7/3.
 */
public class User {

    private String name;

    private String address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

2.2.4 修改启动类读取自定义配置文件

添加自定义xml配置文件读取的相关逻辑。
com.lfqy.springboot.selfdefxml.SelfDefXmlApplication

package com.lfqy.springboot.selfdefxml;

import com.lfqy.springboot.selfdefxml.beans.User;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@SpringBootApplication
public class SelfDefXmlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SelfDefXmlApplication.class);
        System.out.println("The application has been started ....");
        ApplicationContext ac = new ClassPathXmlApplicationContext("SelfDefBeans.xml");
        User user = (User)ac.getBean("user");
        System.out.println(user.getName());
        System.out.println(user.getAddress());
    }
}

2.3 启动和运行

到这里,编码就完成了,工程的目录结构如下。


image.png

运行之后,控制台输出如下:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

2022-07-03 23:54:48.457  INFO 3667 --- [           main] c.l.s.selfdefxml.SelfDefXmlApplication   : Starting SelfDefXmlApplication on ChengdeMBP with PID 3667 (/Users/chengxia/Developer/TrialProject/SpringBoot/SelfDefineXmlTrial/target/classes started by chengxia in /Users/chengxia/Developer/TrialProject)
2022-07-03 23:54:48.461  INFO 3667 --- [           main] c.l.s.selfdefxml.SelfDefXmlApplication   : No active profile set, falling back to default profiles: default
2022-07-03 23:54:48.628  INFO 3667 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@45f45fa1: startup date [Sun Jul 03 23:54:48 CST 2022]; root of context hierarchy
2022-07-03 23:54:51.084  INFO 3667 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-07-03 23:54:51.121  INFO 3667 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-07-03 23:54:51.121  INFO 3667 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2022-07-03 23:54:51.140  INFO 3667 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/chengxia/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2022-07-03 23:54:51.273  INFO 3667 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-07-03 23:54:51.273  INFO 3667 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 2656 ms
2022-07-03 23:54:51.492  INFO 3667 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2022-07-03 23:54:51.497  INFO 3667 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2022-07-03 23:54:51.498  INFO 3667 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2022-07-03 23:54:51.498  INFO 3667 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2022-07-03 23:54:51.498  INFO 3667 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2022-07-03 23:54:51.675  INFO 3667 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-03 23:54:52.034  INFO 3667 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@45f45fa1: startup date [Sun Jul 03 23:54:48 CST 2022]; root of context hierarchy
2022-07-03 23:54:52.153  INFO 3667 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/selfdefxml/hello]}" onto public java.lang.String com.lfqy.springboot.selfdefxml.controller.SelfDefXmlController.hello()
2022-07-03 23:54:52.158  INFO 3667 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2022-07-03 23:54:52.158  INFO 3667 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2022-07-03 23:54:52.190  INFO 3667 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-03 23:54:52.191  INFO 3667 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-03 23:54:52.448  INFO 3667 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2022-07-03 23:54:52.519  INFO 3667 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-07-03 23:54:52.526  INFO 3667 --- [           main] c.l.s.selfdefxml.SelfDefXmlApplication   : Started SelfDefXmlApplication in 4.696 seconds (JVM running for 5.555)
The application has been started ....
2022-07-03 23:54:52.532  INFO 3667 --- [           main] o.s.c.s.ClassPathXmlApplicationContext   : Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7cd1ac19: startup date [Sun Jul 03 23:54:52 CST 2022]; root of context hierarchy
2022-07-03 23:54:52.537  INFO 3667 --- [           main] o.s.b.f.xml.XmlBeanDefinitionReader      : Loading XML bean definitions from class path resource [SelfDefBeans.xml]
Paopao
Beijing

3、实现xml配置文件启动时自动加载

这里,通过实现一个启动时自动初始化的一个servlet来实现。

3.1 新增一个servlet实现类

com.lfqy.springboot.selfdefxml.servlet.StartupServlet

package com.lfqy.springboot.selfdefxml.servlet;

import com.lfqy.springboot.selfdefxml.beans.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

/**
 * Created by chengxia on 2022/7/3.
 */
public class StartupServlet extends HttpServlet {
    private static final long serialVersionUID = 8823372937923792739L;
    public StartupServlet(){}
    public void init(ServletConfig sc) throws ServletException{
        super.init(sc);
        //load the self-deine beans
        ApplicationContext ac = new ClassPathXmlApplicationContext("SelfDefBeans.xml");
        User user = (User)ac.getBean("user");
        System.out.println(user.getName());
        System.out.println(user.getAddress());
    }
}

3.2 在启动类中添加servlet加载逻辑

在启动时加载servlet,为了方便区分,这里新写一个启动类。
com.lfqy.springboot.selfdefxml.SelfDefXmlLoadOnStartupApplication

package com.lfqy.springboot.selfdefxml;

import com.lfqy.springboot.selfdefxml.beans.User;
import com.lfqy.springboot.selfdefxml.servlet.StartupServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@SpringBootApplication
@ServletComponentScan(basePackages = "com.lfqy.springboot.selfdefxml.servlet") //servlet扫描包路径
public class SelfDefXmlLoadOnStartupApplication {
    @Bean
    public ServletRegistrationBean getServletRunOnStartup(){
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StartupServlet());
        //设置Servlet在服务器启动时初始化(执行init方法),如果传入的参数是负数或者没有配置,那么这个Servlet会在第一次被请求时初始化
        servletRegistrationBean.setLoadOnStartup(1);
        //这里随便指定servlet关联度的url,如果不指定,那么默认所有的请求都会到这儿,会有各种奇奇怪怪的问题
        servletRegistrationBean.addUrlMappings("/runOnStartup");
        return servletRegistrationBean;
    }

    public static void main(String[] args) {
        SpringApplication.run(SelfDefXmlLoadOnStartupApplication.class);
        System.out.println("The application has been started ....");
    }
}

3.3 启动和运行

到这里,编码已经完成,工程的目录结构如下:


image.png

运行之后,控制台输出如下:


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.2.RELEASE)

2022-07-04 00:13:45.346  INFO 3789 --- [           main] l.s.s.SelfDefXmlLoadOnStartupApplication : Starting SelfDefXmlLoadOnStartupApplication on ChengdeMBP with PID 3789 (/Users/chengxia/Developer/TrialProject/SpringBoot/SelfDefineXmlTrial/target/classes started by chengxia in /Users/chengxia/Developer/TrialProject)
2022-07-04 00:13:45.350  INFO 3789 --- [           main] l.s.s.SelfDefXmlLoadOnStartupApplication : No active profile set, falling back to default profiles: default
2022-07-04 00:13:45.399  INFO 3789 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@18a70f16: startup date [Mon Jul 04 00:13:45 CST 2022]; root of context hierarchy
2022-07-04 00:13:47.116  INFO 3789 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2022-07-04 00:13:47.155  INFO 3789 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-07-04 00:13:47.156  INFO 3789 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2022-07-04 00:13:47.165  INFO 3789 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/chengxia/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
2022-07-04 00:13:47.244  INFO 3789 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-07-04 00:13:47.244  INFO 3789 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1848 ms
2022-07-04 00:13:47.390  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet startupServlet mapped to [/runOnStartup]
2022-07-04 00:13:47.391  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2022-07-04 00:13:47.394  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2022-07-04 00:13:47.395  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2022-07-04 00:13:47.395  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2022-07-04 00:13:47.395  INFO 3789 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2022-07-04 00:13:47.539  INFO 3789 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-04 00:13:47.765  INFO 3789 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@18a70f16: startup date [Mon Jul 04 00:13:45 CST 2022]; root of context hierarchy
2022-07-04 00:13:47.824  INFO 3789 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/selfdefxml/hello]}" onto public java.lang.String com.lfqy.springboot.selfdefxml.controller.SelfDefXmlController.hello()
2022-07-04 00:13:47.828  INFO 3789 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2022-07-04 00:13:47.830  INFO 3789 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2022-07-04 00:13:47.854  INFO 3789 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-04 00:13:47.854  INFO 3789 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2022-07-04 00:13:47.991  INFO 3789 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2022-07-04 00:13:48.086  INFO 3789 --- [           main] o.s.c.s.ClassPathXmlApplicationContext   : Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@790174f2: startup date [Mon Jul 04 00:13:48 CST 2022]; root of context hierarchy
2022-07-04 00:13:48.090  INFO 3789 --- [           main] o.s.b.f.xml.XmlBeanDefinitionReader      : Loading XML bean definitions from class path resource [SelfDefBeans.xml]
Paopao
Beijing
2022-07-04 00:13:48.190  INFO 3789 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2022-07-04 00:13:48.193  INFO 3789 --- [           main] l.s.s.SelfDefXmlLoadOnStartupApplication : Started SelfDefXmlLoadOnStartupApplication in 3.506 seconds (JVM running for 4.179)
The application has been started ....

参考资料

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

推荐阅读更多精彩内容