Sonar代码质量与技术债

由来

《Sonar code quality testing essential》一书中从七个维度定义了代码的这种内在质量,Sonar开发团队上纲上线的戏称为开发人员七宗罪:

  • 编码规范:是否遵守了编码规范,遵循了最佳实践。

  • 潜在的BUG:可能在最坏情况下出现问题的代码,以及存在安全漏洞的代码。

  • 文档和注释:过少(缺少必要信息)、过多(没有信息量)、过时的文档或注释。

  • 重复代码:违反了Don’tRepeat Yourself原则。

  • 复杂度:代码结构太复杂(如圈复杂度高),难以理解、测试和维护。

  • 测试覆盖率:编写单元测试,特别是针对复杂代码的测试覆盖是否足够。

  • 设计与架构:是否高内聚、低耦合,依赖最少。

参照这些资料,现在我们可以用可测性,可读性,可理解性,容变性等代码可维护性维度的质量属性来衡量代码质量。代码质量指的是代码内在的非功能性的质量,用户不能直接体验到这种质量的好坏,代码质量不好,最直接的“受害者”是开发者或组织自身,因为代码质量好坏直接决定了软件的可维护性成本的高低,例如重复代码会造成维护成本的成倍增加;不规范的代码、不良注释和复杂度过高的代码会增加阅读和理解代码的难度,复杂度过高也会极大增加测试覆盖的难度,耗费过多人力,而缺少测试覆盖的代码会使得定位问题和修复问题的难度加大;结构不良、低内聚高耦合的代码则会使得哪怕是微小的需求变更或功能扩展都无从下手,修改的代价很可能超过了重写的代价。

至此,我们得到了一些定性的办法来衡量代码的质量,我们可以借助一些代码扫描工具来暴露代码的质量问题,也有了相应的重构方法和技巧来应对这些问题。但是,我们还是难以回答某段代码有多好或多差,两段代码相比哪个更好这样的问题,因为我们仍然没有完全解决代码质量的量化问题:同样都是代码质量问题,重复代码和过多注释的危害肯定是不一样的;同样都是方法太复杂,圈复杂度为10的方法和圈复杂度为20的方法相比,危害和修改难度也差别很大。所以我们不能直接用问题的数量来衡量质量,需要找到更精细合理的量化度量方法。

Sonar 介绍

Sonar 是一个用于代码质量管理的开放平台。通过插件机制,Sonar可以集成不同的测试工具,代码分析工具,以及持续集成工具。与持续集成工具(例如 Hudson/Jenkins 等)不同,Sonar 并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD 等)直接显示在 Web 页面上,而是通过不同的插件对这些结果进行再加工处理,通过量化的方式度量代码质量的变化,从而可以方便地对不同规模和种类的工程进行代码质量管理。

在对其他工具的支持方面,Sonar 不仅提供了对 IDE 的支持,可以在 Eclipse和 IntelliJ IDEA 这些工具里联机查看结果;同时 Sonar 还对大量的持续集成工具提供了接口支持,可以很方便地在持续集成中使用 Sonar。

此外,Sonar 的插件还可以对 Java 以外的其他编程语言提供支持,对国际化以及报告文档化也有良好的支持。

sonarQube系统是一个代码质量检测工具 由以下四个组件组成

  • sonarQube服务器 包含三个子进程(web服务(界面管理),搜索服务 计算引擎服务(写入数据库))

  • PostgreSQL数据库提供存储功能

  • 灵活的插件配置

  • 多种sonarqube scanners 分析工具

image.png

使用SonarQube(简称SQ)工作流程

开发者使用开发工具(eclipse,ide)上传代码到SCM(源代码管理器) 系统自动同步代码到某个位置 sonarqube scanners 扫描该代码检查质量 将分析结果 将分析结果推送到SQServer 存储在DB数据库 用户可以使用eclipse插件sonarlint来同步sonarqube服务器配置(java和js版本等)可以实时在线分析

image.png

Sonar 安装(建议采用Docker)

Sonar 的相关下载和文档可以在下面的链接中找到:http://www.sonarqube.org/downloads 。 需要注意最新版的 Sonar 需要至少JDK 1.8及以上版本。

image.png
  • 下载 SonarQube社区版LTS
  • 推荐使用PostgreSQL数据库,打开SonarQube服务器下的conf /sonar.properties。要用那种数据库 就在那个数据库下面进行配置。
    (也可以不配置数据库,会默认采用H2数据库,只是不方便后续数据迁移)
#----- PostgreSQL 8.x/9.x
# If you don't use the schema named "public", please refer to 

http://jira.sonarsource.com/browse/SONAR-5000
sonar.jdbc.url=jdbc:postgresql://localhost/sonar
sonar.jdbc.username=test
sonar.jdbc.password=test
sonar.login=test
sonar.password=test


sonar.jdbc.url=jdbc:postgresql://localhost/sonar
如果数据库中没有sonar这个数据库,就新建一个,或者改为其他的数据库
  • 解压缩,在C:\ sonarqube/ etc / sonarqube

  • 启动SonarQube服务器:

image.png
# On Windows, execute:
C:\sonarqube\bin\windows-x86-xx\StartSonar.bat

# On other operating systems, execute:
/etc/sonarqube/bin/[OS]/sonar.sh console

Docker搭建SonarQube

首先,你需要如下镜像:

postgres 数据库
sonarqube Sonar主体
#可以指定版本
docker pull postgres

#可以指定版本
docker pull sonarqube

docker安装部署postgresql

docker run  -d -p 5432:5432 -e POSTGRES_USER=sonar -e POSTGRES_PASSWORD=sonar -e POSTGRE_DB=sonar -v /lai/postgresql/data:/var/lib/postgresql/data docker.io/postgres

docker安装部署sonarqube,已经有官方镜像可以参考

官方镜像说明:https://github.com/docker-library/docs/tree/master/sonarqube

image.png
image.png

Sonar 登入

在浏览器打开:http://localhost:9000

image.png

sonar跟jenkins类似,也是以插件为主。
sonar安装插件有2种方式:第一种将插件下载完存放在sonar的插件目录,第二种使用web界面来使用安装存放插件路径[/usr/local/sonarqube/extensions/plugins/]。

安装中文插件

登陆:用户名:admin 密码:admin

image.png
image.png

重启才会生效。

生效后界面如下。

image.png

和 jenkins 一样,需要什么插件直接去应用市场下载即可。

安装 sonar 扫描器

Sonar通过SonarQube Scanner(扫描器)来对代码进行分析。

官方下载地址:https://docs.sonarqube.org/display/SCAN/Analyzing+Source+Code

image.png

扫描器也提供插件方式集成到Ant、Maven等项目中。

扫描器和SonarQube服务器关联

下载之后解压zip包,之后进入该目录的conf文件夹下,
打开文件sonar-scanner.properties

编辑文件sonar-scanner/conf/sonar-scanner.properties,修改如下内容:

sonar.host.url=http://localhost:9000   
#如果是远程服务器就填入对应IP     
sonar.sourceEncoding=UTF-8                  

代码扫描

sonar-scanner根据项目目录下的sonar-project.properties来进行扫描

如果想要代码被扫描,就需要在代码路径下放一个配置文件
sonar-project.properties

sonar.projectKey=org.sonarqube:sonarqube-scanner            
#Key值,在SonarQube实例中是唯一标识
sonar.projectName=Example of SonarQube Scanner Usage    
# 设置SonarQube UI显示的名称 
# PS:有人会问这里的名称是否可以是中文名称,我在网上搜索了好多资料都说是不可以的(至少我看到的资料都是)
#     后来自己尝试了一下,答案是可以写成中文的,但是要换一种方式,比如你想把项目名称命名为“测试”,
#     那么在这里就要写成“\u6d4b\u8bd5”,那么下面这个参数就应该这样写“sonar.projectName= \u6d4b\u8bd5”,
#     说白了就是将中文转成Unicode
sonar.projectVersion=1.0                                            
#版本,也会显示在web上面
sonar.sources=src                                     
#软件包存放路径
sonar.sourceEncoding=UTF-8                           
#字体编码

确保sonar-scanner/bin配置一下环境变量,可以输入sonar-scanner -v检测

λ sonar-scanner -v
INFO: Scanner configuration file: C:\Users\lenovo\Desktop\sonar-scanner-3.2.0.1227-windows\bin\..\conf\sonar-scanner.properties
INFO: Project root configuration file: NONE
INFO: SonarQube Scanner 3.2.0.1227
INFO: Java 1.8.0_121 Oracle Corporation (64-bit)
INFO: Windows 8.1 6.3 amd64

然后从终端进入工程根目录,运行sonar-scanner你会看到如下日志

λ sonar-scanner
INFO: Scanner configuration file: C:\Users\lenovo\Desktop\sonar-scanner-3.2.0.1227-windows\bin\..\conf\sonar-scanner.properties
INFO: Project root configuration file: C:\Users\lenovo\Desktop\java\jacoco\sonar-project.properties
INFO: SonarQube Scanner 3.2.0.1227
INFO: Java 1.8.0_121 Oracle Corporation (64-bit)
INFO: Windows 8.1 6.3 amd64
INFO: User cache: C:\Users\lenovo\.sonar\cache
INFO: SonarQube server 7.1.0
INFO: Default locale: "zh_CN", source code encoding: "UTF-8"
INFO: Publish mode
INFO: Load global settings
INFO: Load global settings (done) | time=327ms
INFO: Server id: AWb3dRtEbHtoPAfTpBKi
INFO: User cache: C:\Users\lenovo\.sonar\cache
INFO: Load plugins index
INFO: Load plugins index (done) | time=259ms
INFO: Load/download plugins
INFO: Plugin [l10nzh] defines 'l10nen' as base plugin. This metadata can be removed from manifest of l10n plugins since version 5.2.
INFO: Load/download plugins (done) | time=232635ms
INFO: Process project properties
INFO: Load project repositories
INFO: Load project repositories (done) | time=94ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=170ms
INFO: Load active rules
INFO: Load active rules (done) | time=8004ms
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=197ms
WARN: SCM provider autodetection failed. No SCM provider claims to support this project. Please use sonar.scm.provider to define SCM of your project.
INFO: Project key: Jacoco
INFO: Project base dir: C:\Users\lenovo\Desktop\java\jacoco
INFO: -------------  Scan Jacoco
INFO: Load server rules
INFO: Load server rules (done) | time=12240ms
INFO: Base dir: C:\Users\lenovo\Desktop\java\jacoco
INFO: Working dir: C:\Users\lenovo\Desktop\java\jacoco\.scannerwork
INFO: Source paths: src
INFO: Source encoding: UTF-8, default locale: zh_CN
INFO: Language is forced to java
INFO: Index files
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\java\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\java\com\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\com\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\com\test\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
INFO: 2 files indexed
INFO: Quality profile for java: Sonar way
INFO: Sensor JavaSquidSensor [java]
INFO: Configured Java source version (sonar.java.source): none
INFO: JavaClasspath initialization
WARN: Bytecode of dependencies was not provided for analysis of source files, you might end up with less precise results. Bytecode can be provided using sonar.java.libraries property
INFO: JavaClasspath initialization (done) | time=61ms
INFO: JavaTestClasspath initialization
INFO: JavaTestClasspath initialization (done) | time=1ms
INFO: Java Main Files AST scan
INFO: 2 source files to be analyzed
INFO: Java Main Files AST scan (done) | time=2235ms
INFO: Java Test Files AST scan
INFO: 2/2 source files have been analyzed
INFO: 0 source files to be analyzed
INFO: Java Test Files AST scan (done) | time=5ms
INFO: 0/0 source files have been analyzed
INFO: Sensor JavaSquidSensor [java] (done) | time=3964ms
INFO: Sensor SurefireSensor [java]
INFO: parsing [C:\Users\lenovo\Desktop\java\jacoco\target\surefire-reports]
INFO: Sensor SurefireSensor [java] (done) | time=344ms
INFO: Sensor JaCoCoSensor [java]
WARN: Property 'sonar.jacoco.reportMissing.force.zero' is deprecated and its value will be ignored.
INFO: ------------------------------------------------------------------------
INFO: EXECUTION FAILURE
INFO: ------------------------------------------------------------------------
INFO: Total time: 7:45.906s
INFO: Final Memory: 12M/130M
INFO: ------------------------------------------------------------------------
ERROR: Error during SonarQube Scanner execution
ERROR: Unable to resolve path 'C:UserslenovoDesktopjavajacoco   argetcoverage-reportsjacoco.exec'
ERROR: Caused by: 文件名、目录名或卷标语法不正确。
ERROR:
ERROR: Re-run SonarQube Scanner using the -X switch to enable full debug logging.

C:\Users\lenovo\Desktop\java\jacoco
λ sonar-scanner
INFO: Scanner configuration file: C:\Users\lenovo\Desktop\sonar-scanner-3.2.0.1227-windows\bin\..\conf\sonar-scanner.properties
INFO: Project root configuration file: C:\Users\lenovo\Desktop\java\jacoco\sonar-project.properties
INFO: SonarQube Scanner 3.2.0.1227
INFO: Java 1.8.0_121 Oracle Corporation (64-bit)
INFO: Windows 8.1 6.3 amd64
INFO: User cache: C:\Users\lenovo\.sonar\cache
INFO: SonarQube server 7.1.0
INFO: Default locale: "zh_CN", source code encoding: "UTF-8"
INFO: Publish mode
INFO: Load global settings
INFO: Load global settings (done) | time=451ms
INFO: Server id: AWb3dRtEbHtoPAfTpBKi
INFO: User cache: C:\Users\lenovo\.sonar\cache
INFO: Load plugins index
INFO: Load plugins index (done) | time=233ms
INFO: Load/download plugins
INFO: Plugin [l10nzh] defines 'l10nen' as base plugin. This metadata can be removed from manifest of l10n plugins since version 5.2.
INFO: Load/download plugins (done) | time=97ms
INFO: Process project properties
INFO: Load project repositories
INFO: Load project repositories (done) | time=91ms
INFO: Load quality profiles
INFO: Load quality profiles (done) | time=147ms
INFO: Load active rules
INFO: Load active rules (done) | time=7884ms
INFO: Load metrics repository
INFO: Load metrics repository (done) | time=203ms
WARN: SCM provider autodetection failed. No SCM provider claims to support this project. Please use sonar.scm.provider to define SCM of your project.
INFO: Project key: Jacoco
INFO: Project base dir: C:\Users\lenovo\Desktop\java\jacoco
INFO: -------------  Scan Jacoco
INFO: Load server rules
INFO: Load server rules (done) | time=11988ms
INFO: Base dir: C:\Users\lenovo\Desktop\java\jacoco
INFO: Working dir: C:\Users\lenovo\Desktop\java\jacoco\.scannerwork
INFO: Source paths: src
INFO: Source encoding: UTF-8, default locale: zh_CN
INFO: Language is forced to java
INFO: Index files
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\java\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\main\java\com\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\com\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
WARN: File 'C:\Users\lenovo\Desktop\java\jacoco\src\test\java\com\test\.DS_Store' is ignored because it doesn't belong to the forced language 'java'
INFO: 2 files indexed
INFO: Quality profile for java: Sonar way
INFO: Sensor JavaSquidSensor [java]
INFO: Configured Java source version (sonar.java.source): none
INFO: JavaClasspath initialization
WARN: Bytecode of dependencies was not provided for analysis of source files, you might end up with less precise results. Bytecode can be provided using sonar.java.libraries property
INFO: JavaClasspath initialization (done) | time=37ms
INFO: JavaTestClasspath initialization
INFO: JavaTestClasspath initialization (done) | time=1ms
INFO: Java Main Files AST scan
INFO: 2 source files to be analyzed
INFO: 2/2 source files have been analyzed
INFO: Java Main Files AST scan (done) | time=866ms
INFO: Java Test Files AST scan
INFO: 0 source files to be analyzed
INFO: Java Test Files AST scan (done) | time=1ms
INFO: 0/0 source files have been analyzed
INFO: Sensor JavaSquidSensor [java] (done) | time=2096ms
INFO: Sensor SurefireSensor [java]
INFO: parsing [C:\Users\lenovo\Desktop\java\jacoco\target\surefire-reports]
INFO: Sensor SurefireSensor [java] (done) | time=110ms
INFO: Sensor JaCoCoSensor [java]
WARN: Property 'sonar.jacoco.reportMissing.force.zero' is deprecated and its value will be ignored.
INFO: Analysing C:\Users\lenovo\Desktop\java\jacoco\target\coverage-reports\jacoco.exec
INFO: No information about coverage per test.
INFO: Sensor JaCoCoSensor [java] (done) | time=193ms
INFO: Sensor SonarJavaXmlFileSensor [java]
INFO: Sensor SonarJavaXmlFileSensor [java] (done) | time=0ms
INFO: Sensor Zero Coverage Sensor
INFO: Sensor Zero Coverage Sensor (done) | time=26ms
INFO: Sensor CPD Block Indexer
INFO: Sensor CPD Block Indexer (done) | time=52ms
INFO: No SCM system was detected. You can use the 'sonar.scm.provider' property to explicitly specify it.
INFO: Calculating CPD for 2 files
INFO: CPD calculation finished
INFO: Analysis report generated in 169ms, dir size=27 KB
INFO: Analysis reports compressed in 36ms, zip size=9 KB
INFO: Analysis report uploaded in 839ms
INFO: ANALYSIS SUCCESSFUL, you can browse http://47.107.167.13:9000/dashboard/index/Jacoco
INFO: Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
INFO: More about the report processing at http://47.107.167.13:9000/api/ce/task?id=AWcA4y1ZLxW-5_oLDjWM
INFO: Task total time: 30.465 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 37.660s
INFO: Final Memory: 12M/158M
INFO: ------------------------------------------------------------------------

web查看扫描结果

image.png
image.png

自定义代码规则

在质量配置中,可以自定义想要的代码规则。

首先SonarQube它默认自带了很多规则

image.png

如果这些内置的规则不适合,可以选择创建适合自己的规则

image.png
image.png
image.png

勾选需要的规则

image.png

以上的规则都是只能够选取SonarQube官方提供的,这样的自定义还不够全面,希望能够自己来定义相关的代码规则,而不是引用官方的。

自定义的CheckStyle代码规则

参考:https://www.jianshu.com/p/ff1d800885ce

CheckStyle是SourceForge下的一个项目,提供了一个帮助JAVA开发人员遵守某些编码规范的工具。它能够自动化代码规范检查过程,从而使得开发人员从这项重要,但是枯燥的任务中解脱出来。

CheckStyle检验的主要内容

  • Javadoc注释
  • 命名约定
  • 标题
  • Import语句
  • 体积大小
  • 空白
  • 修饰符
  • 代码问题
  • 类设计

安装CheckStyle插件

image.png

配置自定义的CheckStyle代码规则

配置自定义的CheckStyle代码规则,有两种方法,使用CheckStyle代码规则配置文件启用SonarQube中的CheckStyle相关代码规则,下面一一介绍:

  • 使用CheckStyle代码规则配置文件
    注意:这种方法只有新建一个质量配置时才能用,质量配置创建好后,就不能利用配置文件来配置代码规则了。
image.png

填写好相关信息后,点击创建按钮。这里有几个问题需要注意下:

  • 问题一 配置文件不能以<?xml version="1.0" encoding="UTF-8"?>开头**,否则点击创建按钮时会有如下错误提示:
image.png

因此要把此标签去掉,直接以<module>标签开头,如下图所示:

image.png
  • 问题二 配置文件中不能有重复的规则,否则点击创建按钮时,会有报错提示,比如:
image.png

上图中提示ReturnCountCheck进行了重复配置,看一下配置文件

image.png
  • 问题三 配置文件中不能有规则模板(规则模板后面介绍),当配置文件中有规则模板,点击创建按钮时,会有报错提示,比如:
image.png

上图错误提示的意思是:规则模板checkstyle:com.puppycrawl.tools.checkstyle.checks.coding.FinalLocalVariableCheck不能被激活。这条规则是检测从未改变的局部变量是否添加final修饰词,那么如果我们需要添加这条规则,怎么处理呢?留到启用SonarQube中CheckStyle相关代码规则方法去说。

通过使用配置文件的方法配置自定义的CheckStyle代码规则,或多或少还会有其它问题,要根据提示处理配置文件。所以,一般情况下,不建议使用这种方法

启用SonarQube中CheckStyle相关代码规则

当安装了CheckStyle插件后,相关代码规则已经带有了。只需要根据实际需求进行适配。

image.png

规则配置

规则列表中的规则有两类:非模板规则(有活动按钮,无规则模板的标签)和模板规则(无活动按钮,有规则模板的标签)。

非模板规则
对于非模板规则,我们直接在规则列表中点击列表项的活动按钮即可,在弹出的对话框中再次点击活动即可:

image.png

如果想先了解下规则的内容,也可以先点击规则名称进入详情页,详情页也有激活的入口。

image.png

规则模板
对于规则模板,是没有直接的激活按钮的。需要我们先根据模板创建一条规则,之后再激活创建的规则。

image.png
image.png

点击创建按钮,弹出自定义规则创建框

image.png

创建规则

image.png

在此页面中,可以进行二次编辑、删除、激活等操作

image.png

配置好后,可在配置详情页中点击CheckStyle的链接,以XML的格式查看已配置好的规则,如下图所示:

image.png

质量阀

这是一个非常好的概念用法,特别是针对有质量要求的项目,当不通过质量阀,可以停止进行代码合并,同时可以提供webhook的方式进行关联Jenkins等工具,配置邮件服务来进行提醒。

image.png

对提交新代码进行检测

现在越来越流行的DevOps概念,追求快速发布,而且有质量保证,特别是多分支的情况下,通过结合git diff的对比,对代码托管在 Gitlab 上每次 commit 的文件做代码检测,使用 Sonar GitLab Plugin 插件完成,该插件会针对每次提交修改的文件,添加注释行,同时添加本次提交的代码检测结果的评论,添加的代码检测 Pipelines stage 流程,来控制代码检测流程是否通过,规定需要通过质量阀,才可以合到主干中。通过对比,能够更加保证保量的完成一个高质量的项目。

具体的操作方法看项目组,内部的沟通。可参考https://blog.csdn.net/aixiaoyang168/article/details/78115646/

Jenkins集成

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

推荐阅读更多精彩内容