03 参数绑定、分组校验、数据回显、异常处理

复习

springmvc框架:
DispatcherServlet前端控制器:接收request,进行response
HandlerMapping处理器映射器:根据url查找Handler。(可以通过xml配置方式,注解方式)
HandlerAdapter处理器适配器:根据特定规则去执行Handler,编写Handler时需要按照HandlerAdapter的要求去编写。
Handler处理器(后端控制器):需要程序员去编写,常用注解开发方式。
Handler处理器执行后结果 是ModelAndView,具体开发时Handler返回方法值类型包括 :ModelAndView、String(逻辑视图名)、void(通过在Handler形参中添加request和response,类似原始 servlet开发方式,注意:可以通过指定response响应的结果类型实现json数据输出)
View resolver视图解析器:根据逻辑视图名生成真正的视图(在springmvc中使用View对象表示)
View视图:jsp页面,仅是数据展示,没有业务逻辑。

注解开发:
使用注解方式的处理器映射器和适配器:

<!--注解映射器 -->

  <bean  class=*"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"*/>

<!--注解适配器 -->

  <bean  class=*"org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"*/>

在实际开发,使用<mvc:annotation-driven>代替上边处理器映射器和适配器配置。

@controller注解必须要加,作用标识类是一个Handler处理器。
@requestMapping注解必须要加,作用:
1、对url和Handler的方法进行映射。
2、可以窄化请求映射,设置Handler的根路径,url就是根路径+子路径请求方式
3、可以限制http请求的方法
映射成功后,springmvc框架生成一个Handler对象,对象中只包括 一个映射成功的method。

注解开发中参数绑定:
将request请求过来的key/value的数据(理解一个串),通过转换(参数绑定的一部分),将key/value串转成形参,将转换后的结果传给形参(整个参数绑定过程)。
springmvc所支持参数绑定:
1、默认支持很多类型,HttpServletRequest、response、session、
model/modelMap(将模型数据填充到request域)
2、支持简单数据类型,整型、字符串、日期。。
只要保证request请求的参数名和形参名称一致,自动绑定成功
如果request请求的参数名和形参名称不一致,可以使用@RequestParam(指定request请求的参数名),@RequestParam加在形参的前边。
3、支持pojo类型
只要保证request请求的参数名称和pojo中的属性名一致,自动将request请求的参数设置到pojo的属性中。
注意:形参中即有pojo类型又有简单类型,参数绑定互不影响。
自定义参数绑定:
日期类型绑定自定义:
定义的Converter<源类型,目标类型>接口实现类,比如:
Converter<String,Date>表示:将请求的日期数据串转成java中的日期类型。
注意:要转换的目标类型一定和接收的pojo中的属性类型一致。
将定义的Converter实现类注入到处理器适配器中。

  <mvc:annotation-driven  conversion-service=*"conversionService"*>

</mvc:annotation-driven>

<!-- conversionService -->

  <bean  id=*"conversionService"*

  class=*"org.springframework.format.support.FormattingConversionServiceFactoryBean"*>

  <!-- 转换器 -->

  <property  name=*"converters"*>

  <list>

  <bean  class=*"cn.itcast.ssm.controller.converter.CustomDateConverter"*/>

  </list>

  </property>

  </bean>

springmvc和struts2区别:
springmvc面向方法开发的(更接近service接口的开发方式),struts2面向类开发。
springmvc可以单例开发,struts2只能是多例开发。

课程安排

在商品查询和商品修改功能案例驱动下进行学习:
包装类型pojo参数绑定(掌握)。
集合类型的参数绑定:数组、list、map..
商品修改添加校验,学习springmvc提供校验validation(使用的是hibernate校验框架)
数据回显
统一异常处理(掌握)

上传图片
json数据交互
RESTful支持
拦截器

包装类型pojo参数绑定

需求

商品查询controller方法中实现商品查询条件传入。

实现方法

第一种方法:在形参中 添加HttpServletRequest request参数,通过request接收查询条件参数。

第二种方法:在形参中让包装类型的pojo接收查询条件参数。

分析:
页面传参数的特点:复杂,多样性。条件包括 :用户账号、商品编号、订单信息。。。

如果将用户账号、商品编号、订单信息等放在简单pojo(属性是简单类型)中,pojo类属性比较多,比较乱。

建议使用包装类型的pojo,pojo中属性是pojo。

页面参数和controller方法形参定义

页面参数:

商品名称:
<input name="itemsCustom.name" />

注意:itemsCustom和包装pojo中的属性一致即可。

controller方法形参:

public ModelAndView queryItems(HttpServletRequest request,ItemsQueryVo itemsQueryVo) throws Exception

对应上面input标签中的itemsCustom.name

集合类型绑定

数组绑定

  1. 需求

商品批量删除,用户在页面选择多个商品,批量删除。

  1. 表现层实现

关键:将页面选择(多选)的商品id,传到controller方法的形参,方法形参使用数组接收页面请求的多个商品id。

controller方法定义:


    @RequestMapping("/deleteItems")
    public String deleteItems(Integer[] items_id) throws Exception{
        
        //调用service批量删除商品
        //...
        
        
        
        return "success";
        
        
    }

页面:

itemsList.jsp


<c:forEach items="${itemsList }" var="item">
<tr>
    <td><input type="checkbox" name="items_id" value="${item.id}"/></td>
    <td>${item.name }</td>
    <td>${item.price }</td>
    <td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
    <td>${item.detail }</td>
    
    <td><a href="${pageContext.request.contextPath }/items/editItems.action?id=${item.id}">修改</a></td>

</tr>
</c:forEach>

此时数组已传入

list绑定

  1. 需求

通常在需要批量提交数据时,将提交的数据绑定到list<pojo>中,比如:成绩录入(录入多门课成绩,批量提交),
本例子需求:批量商品修改,在页面输入多个商品信息,将多个商品信息提交到controller方法中。

  1. 表现层实现

controller方法定义:
1、进入批量商品修改页面(页面样式参考商品列表实现)
2、批量修改商品提交
使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list<pojo>属性

ItemsController.java

//批量修改商品页面,将商品信息查询出来,在页面中可以编辑商品信息
    @RequestMapping("/editItemsQuery")
    public ModelAndView editItemsQuery(HttpServletRequest request, ItemsQueryVo itemsQueryVo) throws Exception{
        

        //调用service查找数据库,查询商品列表,这里使用静态数据模拟
        List<ItemsCustom> itemsList = itemsService.findItemsList(itemsQueryVo);
        

        //返回ModelAndView
        ModelAndView modelAndView = new ModelAndView();
        //相当于request的setAttribute,在jsp页面中通过itemsList取数据
        modelAndView.addObject("itemsList",itemsList);
        
        //指定视图
        //下边的路径如果在视图解析器中配置jsp路径的前缀和后缀,/WEB-INF/jsp/items/itemsList.jsp修改为items/itemsList
        modelAndView.setViewName("items/editItemsQuery");
        
        return modelAndView;
        
    }
    
    
    //批量修改商品提交
    //通过ItemsQueryVo接收批量提交的商品信息,将商品信息存储到itemsQueryVo中itemsList属性中
    @RequestMapping("/editItemsAllSubmit")
    public String editItemsAllSubmit(ItemsQueryVo itemsQueryVo) throws Exception{
        
        

        return "success";
        
    }

页面定义
editItemsQuery.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt"  prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查询商品列表</title>
<script type="text/javascript">
function editItemsAllSubmit(){
    //提交form
    document.itemsForm.action="${pageContext.request.contextPath }/items/editItemsAllSubmit.action";
    document.itemsForm.submit();
}
function queryItems(){
    //提交form
    document.itemsForm.action="${pageContext.request.contextPath }/items/queryItems.action";
    document.itemsForm.submit();
}
</script>
</head>
<body> 
<form name="itemsForm" action="${pageContext.request.contextPath }/items/queryItems.action" method="post">
查询条件:
<table width="100%" border=1>
<tr>
<td>
商品名称:<input name="itemsCustom.name" />
</td>
<td><input type="button" value="查询" onclick="queryItems()"/>
<input type="button" value="批量修改提交" onclick="editItemsAllSubmit()"/>
</td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
    <td>商品名称</td>
    <td>商品价格</td>
    <td>生产日期</td>
    <td>商品描述</td>
    <td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item" varStatus="status">
<tr>    

    <td><input name="itemsList[${status.index }].name" value="${item.name }"/></td>
    <td><input name="itemsList[${status.index }].price" value="${item.price }"/></td>
    <td><input name="itemsList[${status.index }].createtime" value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
    <td><input name="itemsList[${status.index }].detail" value="${item.detail }"/></td>


</tr>
</c:forEach>

</table>
</form>
</body>

</html>

map绑定

也通过在包装pojo中定义map类型属性。

在包装类中定义Map对象,并添加get/set方法,action使用包装对象接收。
包装类中定义Map对象如下:

**Public class** QueryVo {

private Map<String, Object> itemInfo = new HashMap<String, Object>();

 //get/set方法..

}

页面定义如下:

<tr>
<td>学生信息:</td>
<td>
姓名:<inputtype="text"name="itemInfo['name']"/>
年龄:<inputtype="text"name="itemInfo['price']"/>
.. .. ..
</td>
</tr>

Contrller方法定义如下:

public String useraddsubmit(Model model,QueryVo queryVo)throws Exception{

System.out.println(queryVo.getStudentinfo());

}

springmvc校验

校验理解

项目中,通常使用较多是前端的校验,比如页面中js校验。对于安全要求较高点建议在服务端进行校验。

服务端校验:
控制层conroller:校验页面请求的参数的合法性。在服务端控制层conroller校验,不区分客户端类型(浏览器、手机客户端、远程调用)
业务层service(使用较多):主要校验关键业务参数,仅限于service接口中使用的参数。
持久层dao:一般是不校验的。

springmvc校验需求

springmvc使用hibernate的校验框架validation(和hibernate没有任何关系)。

校验思路:
页面提交请求的参数,请求到controller方法中,使用validation进行校验。如果校验出错,将错误信息展示到页面。
具体需求:
商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。

环境准备

hibernate的校验框架validation所需要jar包:

配置校验器

springmvc.xml

<!-- 校验器 spring提供的校验接口 -->
    <bean id="validator"
        class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <!-- 校验器-->
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
        <!-- 指定校验使用的资源文件,如果不指定则默认使用classpath下的ValidationMessages.properties -->
        <property name="validationMessageSource" ref="messageSource" />
    </bean>
    
    <!-- 校验错误信息配置文件 -->
    <bean id="messageSource"
        class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- 资源文件名-->
        <property name="basenames">   
         <list>    
            <value>classpath:CustomValidationMessages</value> 
         </list>   
        </property>
        <!-- 资源文件编码格式 -->
        <property name="fileEncodings" value="utf-8" />
        <!-- 对资源文件内容缓存时间,单位秒 -->
        <property name="cacheSeconds" value="120" />
    </bean>

校验器注入到处理器适配器中

<mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>

在pojo中添加校验规则

在ItemsCustom.java中添加校验规则:

CustomValidationMessages.properties

在CustomValidationMessages.properties配置校验错误信息:

捕获校验错误信息

ItemsController.java

//商品修改信息提交
    //在需要校验的pojo前边添加@Validated注解,在需要校验的pojo后边添加 BindingResult bindingResult接收校验出错的信息
    //校验多个pojo,@Validated和BindingResult bindingResult配对出现,并且形参顺序是固定的(一前一后)。
    @RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(HttpServletRequest request, Integer id,
            @Validated ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception{
        
        //获取校验的错误信息
        if(bindingResult.hasErrors()) {
            //输出错误信息
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            
            for(ObjectError objectError : allErrors) {
                //打印
                System.out.println(objectError.getDefaultMessage());
            }
        }
        
        //调用service更新商品信息,页面需要将商品信息传到此方法
        itemsService.updateItems(id, itemsCustom);
        
        
        //重定向到商品列表                        一个controller中不用加根路径
        //重定向
        //return "redirect:queryItems.action";
        
        //转发
        return "forward:queryItems.action";
        
        
    }

属性文件的编码不能轻易修改,在加载时不知道为什么还是用iso8859传输,输入到控制台的都是乱码

在页面显示校验错误信息

在controller中将错误信息传到页面即可。

@RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(Model model,HttpServletRequest request, Integer id,
            @Validated ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception{
        
        //获取校验的错误信息
        if(bindingResult.hasErrors()) {
            //输出错误信息
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            
            for(ObjectError objectError : allErrors) {
                //打印
                System.out.println(objectError.getDefaultMessage());
            }
            //将错误信息传到页面
            model.addAttribute("allErrors", allErrors);
            //出错重新到商品修改页面
            return "items/editItems";
        }
        
        //调用service更新商品信息,页面需要将商品信息传到此方法
        itemsService.updateItems(id, itemsCustom);
        
        return "forward:queryItems.action";
        
        
    }

editItems.jsp

<!-- 显示错误信息 -->
<c:if test="${allErrors!=null }">
    <c:forEach items="${allErrors }" var="error">
        ${error.defaultMessage}
    </c:forEach>
</c:if>

页面显示错误信息:

分组校验

  1. 需求

在pojo中定义校验规则,而pojo是被多个 controller所共用,当不同的controller方法对同一个pojo进行校验,但是每个controller方法需要不同的校验。

解决方法:
定义多个校验分组(其实是一个java接口),分组中定义有哪些规则
每个controller方法使用不同的校验分组

  1. 校验分组

ValidGroup1.java

package cn.itcast.ssm.controller.validation;

/*
 * 校验分组
 * */
public interface ValidGroup1 {

    //接口中不需要定义任何方法,仅是对不同的检验规则进行分组
    //此分组只校验商品名称长度
    
}

  1. 在校验规则中添加分组

Items.java

public class Items {
    private Integer id;

    
    //校验名称在1到30个字符之间
    //message就是提示信息,不能直接提示请输入...这样是硬编码,把它写到配置文件CustomValidationMessages.properties中
    //groups:此校验属于哪个分组,groups可以定义多个分组
    @Size(min=1,max=30,message="{items.name.length.error}", groups= {ValidGroup1.class})
    private String name;

  1. 在controller方法使用指定分组的校验
//value= {ValidGroup1.class}指定使用ValidGroup1分组的校验
    @RequestMapping("/editItemsSubmit")
    public String editItemsSubmit(Model model,HttpServletRequest request, Integer id,
            @Validated(value= {ValidGroup1.class}) ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception{

数据回显

什么数据回显

提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面。

pojo数据回显方法

1、springmvc默认对pojo数据进行回显。
pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

使用@ModelAttribute指定pojo回显到页面在request中的key

2、@ModelAttribute还可以将方法的返回值传到页面

在商品查询列表页面,通过商品类型查询商品信息。
在controller中定义商品类型查询方法,最终将商品类型传到页面。

//商品分类
    @ModelAttribute("itemtypes")
    public Map<String, String> getItemTypes(){
        
        Map<String, String> itemTypes = new HashMap<String,String>();
        itemTypes.put("101", "数码");
        itemTypes.put("102", "母婴");
        
        return itemTypes;
    }

页面上可以得到itemTypes数据。

商品类型:
<select name="itemtype">
    <c:forEach items="${itemtypes }" var="itemtype">
        <option value="${itemtype.key }">${itemtype.value }</option>        
    </c:forEach>
</select>

3、使用最简单方法使用model,可以不用@ModelAttribute

//可以直接使用model将提交的pojo回显到页面
            model.addAttribute("items", itemsCustom);

简单类型数据回显

使用最简单方法使用model。

model.addAttribute("id", id);

异常处理

异常处理思路

系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

springmvc提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。

自定义异常类

对不同的异常类型定义异常类,继承Exception。

CustomException.java

package cn.itcast.ssm.exception;

/*
 * 系统 自定义异常类,针对预期的异常,需要在程序中抛出此类的异常
 */
public class CustomException extends Exception {
    
    //异常信息
    public String message;
    
    public CustomException(String message){
        super(message);
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
    
    

}

全局异常处理器

思路:
系统遇到异常,在程序中手动抛出,dao抛给service、service给controller、controller抛给前端控制器,前端控制器调用全局异常处理器。

全局异常处理器处理思路:

解析出异常类型

如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示

如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)

springmvc提供一个HandlerExceptionResolver接口

全局异常处理器
CustomExceptionResolver.java

package cn.itcast.ssm.exception;

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

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

/*
 * 全局异常处理器 
 */
public class CustomExceptionResolver implements HandlerExceptionResolver {

    /**
     * (非 Javadoc)
     * <p>Title: resolveException</p>
     * <p>Description: </p>
     * @param request
     * @param response
     * @param handler
     * @param ex 系统 抛出的异常
     * @return
     * @see org.springframework.web.servlet.HandlerExceptionResolver#resolveException(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
     */
    @Override
    public ModelAndView resolveException(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex) {
        //handler就是处理器适配器要执行Handler对象(只有method)
        
//      解析出异常类型
//      如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示
//      String message = null;
//      if(ex instanceof CustomException){
//          message = ((CustomException)ex).getMessage();
//      }else{
////            如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)
//          message="未知错误";
//      }
        
        //上边代码变为
        CustomException customException = null;
        if(ex instanceof CustomException){
            customException = (CustomException)ex;
        }else{
            customException = new CustomException("未知错误");
        }
        
        //错误信息
        String message = customException.getMessage();
        
        
        ModelAndView modelAndView = new ModelAndView();
        
        //将错误信息传到页面
        modelAndView.addObject("message", message);
        
        //指向错误页面
        modelAndView.setViewName("error");

        
        return modelAndView;
    }

}

error.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>错误提示</title>
</head>
<body>
${message }
</body>
</html>
  1. 在springmvc.xml配置全局异常处理器

springmvc.xml

<!-- 全局异常处理器
        只要实现HandlerExceptionResolver接口就是全局异常处理器
        写多个,只有一个起作用
     -->
    <bean class="cn.itcast.ssm.exception.CustomExceptionResolver"></bean>

异常测试

在controller、service、dao中任意一处需要手动抛出异常。
如果是程序中手动抛出的异常,在错误页面中显示自定义的异常信息,如果不是手动抛出异常说明是一个运行时异常,在错误页面只显示“未知错误”。

在商品修改的controller方法中抛出异常 .

//判断商品是否为空,根据id没有查询到商品,抛出异常、提示用户商品信息不存在
        if(itemsCustom == null) {
            throw new CustomException("修改的商品信息不存在");
        }

在service接口中抛出异常:

如果与业务功能相关的异常,建议在service中抛出异常。
与业务功能没有关系的异常,建议在controller中抛出。

上边的功能,建议在service中抛出异常。

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

推荐阅读更多精彩内容