springboot整合RabbitMQ

轉(zhuǎn)載地址:https://www.cnblogs.com/hlhdidi/p/6535677.html


springboot學(xué)習(xí)筆記-6 springboot整合RabbitMQ

一 RabbitMQ的介紹 

  RabbitMQ是消息中間件的一種,消息中間件即分布式系統(tǒng)中完成消息的發(fā)送和接收的基礎(chǔ)軟件.這些軟件有很多,包括ActiveMQ(apache公司的),RocketMQ(阿里巴巴公司的,現(xiàn)已經(jīng)轉(zhuǎn)讓給apache).

消息中間件最主要的作用是解耦,中間件最標(biāo)準(zhǔn)的用法是生產(chǎn)者生產(chǎn)消息傳送到隊(duì)列,消費(fèi)者從隊(duì)列中拿取消息并處理,生產(chǎn)者不用關(guān)心是誰來消費(fèi),消費(fèi)者不用關(guān)心誰在生產(chǎn)消息,從而達(dá)到解耦的目的;在分布式的系統(tǒng)中,消息隊(duì)列也會被用在很多其它的方面,比如:分布式事務(wù)的支持,RPC的調(diào)用等等;

RabbitMQ是實(shí)現(xiàn)AMQP(高級消息隊(duì)列協(xié)議)的消息中間件的一種,主要是為了實(shí)現(xiàn)系統(tǒng)之間的雙向解耦而實(shí)現(xiàn)的。當(dāng)生產(chǎn)者大量產(chǎn)生數(shù)據(jù)時(shí),消費(fèi)者無法快速消費(fèi),那么需要一個(gè)中間層。保存這個(gè)數(shù)據(jù);AMQP,即Advanced Message Queuing Protocol,高級消息隊(duì)列協(xié)議,是應(yīng)用層協(xié)議的一個(gè)開放標(biāo)準(zhǔn),為面向消息的中間件設(shè)計(jì)。消息中間件主要用于組件之間的解耦,消息的發(fā)送者無需知道消息使用者的存在,反之亦然。AMQP的主要特征是面向消息、隊(duì)列、路由(包括點(diǎn)對點(diǎn)和發(fā)布/訂閱)、可靠性、安全;RabbitMQ是一個(gè)開源的AMQP實(shí)現(xiàn),服務(wù)器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系統(tǒng)中存儲轉(zhuǎn)發(fā)消息;

通常隊(duì)列服務(wù), 會有三個(gè)概念: 發(fā)消息者、隊(duì)列、收消息者,RabbitMQ 在這個(gè)基本概念之上, 多做了一層抽象, 在發(fā)消息者和 隊(duì)列之間, 加入了交換器 (Exchange). 這樣發(fā)消息者和隊(duì)列就沒有直接聯(lián)系, 轉(zhuǎn)而變成發(fā)消息者把消息給交換器, 交換器根據(jù)調(diào)度策略再把消息再給隊(duì)列。


RabbitMQ圖解

左側(cè) P 代表 生產(chǎn)者,也就是往 RabbitMQ 發(fā)消息的程序。

中間即是 RabbitMQ,其中包括了 交換機(jī) 和 隊(duì)列。

右側(cè) C 代表 消費(fèi)者,也就是往 RabbitMQ 拿消息的程序


虛擬主機(jī):一個(gè)虛擬主機(jī)持有一組交換機(jī)、隊(duì)列綁定。為什么需要多個(gè)虛擬主機(jī)呢?很簡單,RabbitMQ當(dāng)中,用戶只能在虛擬主機(jī)的粒度進(jìn)行權(quán)限控制。?因此,如果需要禁止A組訪問B組的交換機(jī)/隊(duì)列/綁定,必須為A和B分別創(chuàng)建一個(gè)虛擬主機(jī)。每一個(gè)RabbitMQ服務(wù)器都有一個(gè)默認(rèn)的虛擬主機(jī)“/”。

交換機(jī)Exchange 用于轉(zhuǎn)發(fā)消息,但是它不會做存儲?,如果沒有 Queue bind 到 Exchange 的話,它會直接丟棄掉 Producer 發(fā)送過來的消息。

這里有一個(gè)比較重要的概念:路由鍵?。消息到交換機(jī)的時(shí)候,交互機(jī)會轉(zhuǎn)發(fā)到對應(yīng)的隊(duì)列中,那么究竟轉(zhuǎn)發(fā)到哪個(gè)隊(duì)列,就要根據(jù)該路由鍵。

綁定:也就是交換機(jī)需要和隊(duì)列相綁定,這其中如上圖所示,是的關(guān)系


交換機(jī)(Exchange)

交換機(jī)的功能主要是接收消息并且轉(zhuǎn)發(fā)到綁定的隊(duì)列,交換機(jī)不存儲消息,在啟用ack模式后,交換機(jī)找不到隊(duì)列會返回錯(cuò)誤。交換機(jī)有四種類型:Direct, topic, Headers and Fanout

Direct:direct 類型的行為是"先匹配, 再投送". 即在綁定時(shí)設(shè)定一個(gè)?routing_key, 消息的routing_key?匹配時(shí), 才會被交換器投送到綁定的隊(duì)列中去.

Topic:按規(guī)則轉(zhuǎn)發(fā)消息(最靈活)

Headers:設(shè)置header attribute參數(shù)類型的交換機(jī)

Fanout:轉(zhuǎn)發(fā)消息到所有綁定隊(duì)列


交換機(jī)類型的介紹如下

Direct Exchange

Direct Exchange是RabbitMQ默認(rèn)的交換機(jī)模式,也是最簡單的模式,根據(jù)key全文匹配去尋找隊(duì)列。


Direct Exchange交換機(jī)模式

第一個(gè) X - Q1 就有一個(gè) binding key,名字為 orange; X - Q2 就有 2 個(gè) binding key,名字為 black 和 green。當(dāng)消息中的 路由鍵 和 這個(gè) binding key 對應(yīng)上的時(shí)候,那么就知道了該消息去到哪一個(gè)隊(duì)列中。

Ps:為什么 X 到 Q2 要有 black,green,2個(gè) binding key呢,一個(gè)不就行了嗎? - 這個(gè)主要是因?yàn)榭赡苡钟?Q3,而Q3只接受 black 的信息,而Q2不僅接受black 的信息,還接受 green 的信息。

Topic Exchange

Topic Exchange 轉(zhuǎn)發(fā)消息主要是根據(jù)通配符。?在這種交換機(jī)下,隊(duì)列和交換機(jī)的綁定會定義一種路由模式,那么,通配符就要在這種路由模式和路由鍵之間匹配后交換機(jī)才能轉(zhuǎn)發(fā)消息;

在這種交換機(jī)模式下:

路由鍵必須是一串字符,用句號(.) 隔開,比如說 agreements.us,或者 agreements.eu.stockholm 等。

路由模式必須包含一個(gè) 星號(*),主要用于匹配路由鍵指定位置的一個(gè)單詞,比如說,一個(gè)路由模式是這樣子:agreements..b.*,那么就只能匹配路由鍵是這樣子的:第一個(gè)單詞是 agreements,第四個(gè)單詞是 b。 井號(#)就表示相當(dāng)于一個(gè)或者多個(gè)單詞,例如一個(gè)匹配模式是agreements.eu.berlin.#,那么,以agreements.eu.berlin開頭的路由鍵都是可以的。

具體代碼發(fā)送的時(shí)候還是一樣,第一個(gè)參數(shù)表示交換機(jī),第二個(gè)參數(shù)表示routing key,第三個(gè)參數(shù)即消息。如下:

rabbitTemplate.convertAndSend("testTopicExchange","key1.a.c.key2", " this is RabbitMQ!");

topic 和 direct 類似, 只是匹配上支持了"模式", 在"點(diǎn)分"的 routing_key 形式中, 可以使用兩個(gè)通配符:

*表示一個(gè)詞.

#表示零個(gè)或多個(gè)詞

Headers Exchange

headers 也是根據(jù)規(guī)則匹配, 相較于 direct 和 topic 固定地使用 routing_key , headers 則是一個(gè)自定義匹配規(guī)則的類型.

在隊(duì)列與交換器綁定時(shí), 會設(shè)定一組鍵值對規(guī)則, 消息中也包括一組鍵值對( headers 屬性), 當(dāng)這些鍵值對有一對, 或全部匹配時(shí), 消息被投送到對應(yīng)隊(duì)列.

Fanout Exchange

Fanout Exchange 消息廣播的模式,不管路由鍵或者是路由模式,會把消息發(fā)給綁定給它的全部隊(duì)列,如果配置了routing_key會被忽略。



消息中間件的工作過程可以用生產(chǎn)者消費(fèi)者模型來表示.即,生產(chǎn)者不斷的向消息隊(duì)列發(fā)送信息,而消費(fèi)者從消息隊(duì)列中消費(fèi)信息.具體過程如下:

從上圖可看出,對于消息隊(duì)列來說,生產(chǎn)者,消息隊(duì)列,消費(fèi)者是最重要的三個(gè)概念,生產(chǎn)者發(fā)消息到消息隊(duì)列中去,消費(fèi)者監(jiān)聽指定的消息隊(duì)列,并且當(dāng)消息隊(duì)列收到消息之后,接收消息隊(duì)列傳來的消息,并且給予相應(yīng)的處理.消息隊(duì)列常用于分布式系統(tǒng)之間互相信息的傳遞.

  對于RabbitMQ來說,除了這三個(gè)基本模塊以外,還添加了一個(gè)模塊,即交換機(jī)(Exchange).它使得生產(chǎn)者和消息隊(duì)列之間產(chǎn)生了隔離,生產(chǎn)者將消息發(fā)送給交換機(jī),而交換機(jī)則根據(jù)調(diào)度策略把相應(yīng)的消息轉(zhuǎn)發(fā)給對應(yīng)的消息隊(duì)列.那么RabitMQ的工作流程如下所示:


緊接著說一下交換機(jī).交換機(jī)的主要作用是接收相應(yīng)的消息并且綁定到指定的隊(duì)列.交換機(jī)有四種類型,分別為Direct,topic,headers,Fanout.

  Direct是RabbitMQ默認(rèn)的交換機(jī)模式,也是最簡單的模式.即創(chuàng)建消息隊(duì)列的時(shí)候,指定一個(gè)BindingKey.當(dāng)發(fā)送者發(fā)送消息的時(shí)候,指定對應(yīng)的Key.當(dāng)Key和消息隊(duì)列的BindingKey一致的時(shí)候,消息將會被發(fā)送到該消息隊(duì)列中.

  topic轉(zhuǎn)發(fā)信息主要是依據(jù)通配符,隊(duì)列和交換機(jī)的綁定主要是依據(jù)一種模式(通配符+字符串),而當(dāng)發(fā)送消息的時(shí)候,只有指定的Key和該模式相匹配的時(shí)候,消息才會被發(fā)送到該消息隊(duì)列中.

  headers也是根據(jù)一個(gè)規(guī)則進(jìn)行匹配,在消息隊(duì)列和交換機(jī)綁定的時(shí)候會指定一組鍵值對規(guī)則,而發(fā)送消息的時(shí)候也會指定一組鍵值對規(guī)則,當(dāng)兩組鍵值對規(guī)則相匹配的時(shí)候,消息會被發(fā)送到匹配的消息隊(duì)列中.

  Fanout是路由廣播的形式,將會把消息發(fā)給綁定它的全部隊(duì)列,即便設(shè)置了key,也會被忽略.

二.SpringBoot整合RabbitMQ(Direct模式)

  SpringBoot整合RabbitMQ非常簡單!感覺SpringBoot真的極大簡化了開發(fā)的搭建環(huán)境的時(shí)間..這樣我們程序員就可以把更多的時(shí)間用在業(yè)務(wù)上了,下面開始搭建環(huán)境:

  首先創(chuàng)建兩個(gè)maven工程,這是為了模擬分布式應(yīng)用系統(tǒng)中,兩個(gè)應(yīng)用之間互相交流的過程,一個(gè)發(fā)送者(Sender),一個(gè)接收者(Receiver)


緊接著,配置pom.xml文件,注意其中用到了springboot對于AMQP(高級消息隊(duì)列協(xié)議,即面向消息的中間件的設(shè)計(jì))

<parent>

? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? <artifactId>spring-boot-starter-parent</artifactId>

? ? ? ? <version>1.4.0.RELEASE</version>

? ? </parent>

? ? <properties>

? ? ? ? <java.version>1.7</java.version>

? ? ? ? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

? ? </properties>

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-devtools</artifactId>

? ? ? ? ? ? <optional>true</optional>

? ? ? ? ? ? <scope>true</scope>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-test</artifactId>

? ? ? ? ? ? <scope>test</scope>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-actuator</artifactId>

? ? ? ? </dependency>

? ? ? ? <!-- 添加springboot對amqp的支持 -->

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-amqp</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-tomcat</artifactId>

? ? ? ? ? ? <scope>provided</scope>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.apache.tomcat.embed</groupId>

? ? ? ? ? ? <artifactId>tomcat-embed-jasper</artifactId>

? ? ? ? ? ? <scope>provided</scope>

? ? ? ? </dependency>

? ? </dependencies>

緊接著,我們編寫發(fā)送者相關(guān)的代碼.首先毫無疑問,要書寫啟動類:

@SpringBootApplication

public class App{

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(App.class, args);

? ? }

}

接著在application.properties中,去編輯和RabbitMQ相關(guān)的配置信息,配置信息的代表什么內(nèi)容根據(jù)鍵就能很直觀的看出了.這里端口是5672,不是15672...15672是管理端的端口!

spring.application.name=spirng-boot-rabbitmq-sender

spring.rabbitmq.host=127.0.0.1spring.rabbitmq.port=5672spring.rabbitmq.username=guest

spring.rabbitmq.password=guest

 隨后,配置Queue(消息隊(duì)列).那注意由于采用的是Direct模式,需要在配置Queue的時(shí)候,指定一個(gè)鍵,使其和交換機(jī)綁定.

@Configuration

public class SenderConf {

? ? @Bean

? ? public Queue queue() {

? ? ? ? ? return new Queue("queue");

? ? }

}

接著就可以發(fā)送消息啦!在SpringBoot中,我們使用AmqpTemplate去發(fā)送消息!代碼如下:

@Component

public class HelloSender {

? ? @Autowired

? ? private AmqpTemplate template;


? ? public void send() {

? ? template.convertAndSend("queue","hello,rabbit~");

? ? }

}

編寫測試類!這樣我們的發(fā)送端代碼就編寫完了~

@SpringBootTest(classes=App.class)

@RunWith(SpringJUnit4ClassRunner.class)

public class TestRabbitMQ {


? ? @Autowired

? ? private HelloSender helloSender;

? ? @Test

? ? public void testRabbit() {

? ? ? ? helloSender.send();

? ? }

}

接著我們編寫接收端.接收端的pom文件,application.properties(修改spring.application.name),Queue配置類,App啟動類都是一致的!這里省略不計(jì).主要在于我們需要配置監(jiān)聽器去監(jiān)聽綁定到的消息隊(duì)列,當(dāng)消息隊(duì)列有消息的時(shí)候,予以接收,代碼如下:

@Component

public class HelloReceive {

? ? @RabbitListener(queues="queue")? ? //監(jiān)聽器監(jiān)聽指定的Queue

? ? public void processC(String str) {

? ? ? ? System.out.println("Receive:"+str);

? ? }

}

接下來就可以測試?yán)?首先啟動接收端的應(yīng)用,緊接著運(yùn)行發(fā)送端的單元測試,接收端應(yīng)用打印出來接收到的消息,測試即成功!

  需要注意的地方,Direct模式相當(dāng)于一對一模式,一個(gè)消息被發(fā)送者發(fā)送后,會被轉(zhuǎn)發(fā)到一個(gè)綁定的消息隊(duì)列中,然后被一個(gè)接收者接收!

  實(shí)際上RabbitMQ還可以支持發(fā)送對象:當(dāng)然由于涉及到序列化和反序列化,該對象要實(shí)現(xiàn)Serilizable接口.HelloSender做出如下改寫:

public void send() {

? ? ? ? User user=new User();? ? //實(shí)現(xiàn)Serializable接口

? ? ? ? user.setUsername("hlhdidi");

? ? ? ? user.setPassword("123");

? ? ? ? template.convertAndSend("queue",user);


}

HelloReceiver做出如下改寫:

@RabbitListener(queues="queue")//監(jiān)聽器監(jiān)聽指定的Queuepublicvoidprocess1(User user) {//用User作為參數(shù)System.out.println("Receive1:"+user);

? ? }

三.SpringBoot整合RabbitMQ(Topic轉(zhuǎn)發(fā)模式)

  首先我們看發(fā)送端,我們需要配置隊(duì)列Queue,再配置交換機(jī)(Exchange),再把隊(duì)列按照相應(yīng)的規(guī)則綁定到交換機(jī)上:

@Configuration

public class SenderConf {

? ? ? ? @Bean(name="message")

? ? ? ? public Queue queueMessage() {

? ? ? ? ? ? return new Queue("topic.message");

? ? ? ? }

? ? ? ? @Bean(name="messages")

? ? ? ? public Queue queueMessages() {

? ? ? ? ? ? return new Queue("topic.messages");

? ? ? ? }

? ? ? ? @Bean

? ? ? ? public TopicExchange exchange() {

? ? ? ? ? ? return new TopicExchange("exchange");

? ? ? ? }

? ? ? ? @Bean

? ? ? ? Binding bindingExchangeMessage(@Qualifier("message") Queue queueMessage, TopicExchange exchange) {

? ? ? ? ? ? return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");

? ? ? ? }

? ? ? ? @Bean

? ? ? ? Binding bindingExchangeMessages(@Qualifier("messages") Queue queueMessages, TopicExchange exchange) {

? ? ? ? ? ? return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");//*表示一個(gè)詞,#表示零個(gè)或多個(gè)詞

? ? ? ? }

}

而在接收端,我們配置兩個(gè)監(jiān)聽器,分別監(jiān)聽不同的隊(duì)列:

@RabbitListener(queues="topic.message") //監(jiān)聽器監(jiān)聽指定的Queue

? ? public void process1(String str) {? ?

? ? ? ? System.out.println("message:"+str);

? ? }

? ? @RabbitListener(queues="topic.messages")? ? //監(jiān)聽器監(jiān)聽指定的Queue

? ? public void process2(String str) {

? ? ? ? System.out.println("messages:"+str);

? ? }

 好啦!接著我們可以進(jìn)行測試了!首先我們發(fā)送如下內(nèi)容:

templateConvertAndSend("exchange","topic.message","hello,rabbit!");

方法的第一個(gè)參數(shù)是交換機(jī)名稱,第二個(gè)參數(shù)是發(fā)送的key,第三個(gè)參數(shù)是內(nèi)容,RabbitMQ將會根據(jù)第二個(gè)參數(shù)去尋找有沒有匹配此規(guī)則的隊(duì)列,如果有,則把消息給它,如果有不止一個(gè),則把消息分發(fā)給匹配的隊(duì)列(每個(gè)隊(duì)列都有消息!),顯然在我們的測試中,參數(shù)2匹配了兩個(gè)隊(duì)列,因此消息將會被發(fā)放到這兩個(gè)隊(duì)列中,而監(jiān)聽這兩個(gè)隊(duì)列的監(jiān)聽器都將收到消息!那么如果把參數(shù)2改為topic.messages呢?顯然只會匹配到一個(gè)隊(duì)列,那么process2方法對應(yīng)的監(jiān)聽器收到消息!

四.SpringBoot整合RabbitMQ(Fanout Exchange形式)

  那前面已經(jīng)介紹過了,Fanout Exchange形式又叫廣播形式,因此我們發(fā)送到路由器的消息會使得綁定到該路由器的每一個(gè)Queue接收到消息,這個(gè)時(shí)候就算指定了Key,或者規(guī)則(即上文中convertAndSend方法的參數(shù)2),也會被忽略!那么直接上代碼,發(fā)送端配置如下:

@Configuration

public class SenderConf {

? ? ? ? @Bean(name="Amessage")

? ? ? ? public Queue AMessage() {

? ? ? ? ? ? return new Queue("fanout.A");

? ? ? ? }

? ? ? ? @Bean(name="Bmessage")

? ? ? ? public Queue BMessage() {

? ? ? ? ? ? return new Queue("fanout.B");

? ? ? ? }

? ? ? ? @Bean(name="Cmessage")

? ? ? ? public Queue CMessage() {

? ? ? ? ? ? return new Queue("fanout.C");

? ? ? ? }

? ? ? ? @Bean

? ? ? ? FanoutExchange fanoutExchange() {

? ? ? ? ? ? return new FanoutExchange("fanoutExchange");//配置廣播路由器

? ? ? ? }

? ? ? ? @Bean

? ? ? ? Binding bindingExchangeA(@Qualifier("Amessage") Queue AMessage,FanoutExchange fanoutExchange) {

? ? ? ? ? ? return BindingBuilder.bind(AMessage).to(fanoutExchange);

? ? ? ? }

? ? ? ? @Bean

? ? ? ? Binding bindingExchangeB(@Qualifier("Bmessage") Queue BMessage, FanoutExchange fanoutExchange) {

? ? ? ? ? ? return BindingBuilder.bind(BMessage).to(fanoutExchange);

? ? ? ? }

? ? ? ? @Bean

? ? ? ? Binding bindingExchangeC(@Qualifier("Cmessage") Queue CMessage, FanoutExchange fanoutExchange) {

? ? ? ? ? ? return BindingBuilder.bind(CMessage).to(fanoutExchange);

? ? ? ? }


}

發(fā)送端使用如下代碼發(fā)送:

templateConvertAndSend("fanoutExchange","","xixi,rabbit!");//參數(shù)2將被忽略

接收端監(jiān)聽器配置如下:

@Component

public class HelloReceive {

? ? @RabbitListener(queues="fanout.A")

? ? public void processA(String str1) {

? ? ? ? System.out.println("ReceiveA:"+str1);

? ? }

? ? @RabbitListener(queues="fanout.B")

? ? public void processB(String str) {

? ? ? ? System.out.println("ReceiveB:"+str);

? ? }

? ? @RabbitListener(queues="fanout.C")

? ? public void processC(String str) {

? ? ? ? System.out.println("ReceiveC:"+str);

? ? }

}

運(yùn)行測試代碼,發(fā)現(xiàn)三個(gè)監(jiān)聽器都接收到了數(shù)據(jù),測試成功!

第一個(gè) X - Q1 就有一個(gè) binding key,名字為 orange; X - Q2 就有 2 個(gè) binding key,名字為 black 和 green。當(dāng)消息中的 路由鍵 和 這個(gè) binding key 對應(yīng)上的時(shí)候,那么就知道了該消息去到哪一個(gè)隊(duì)列中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,093評論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內(nèi)容