SpringMVC框架笔记02_参数绑定返回值文件上传异常处理器JSON数据交互_拦截器

第1章 高级参数的绑定

1.1 参数的分类

  1. 默认参数绑定:requestresponsesessionmodel
  2. 基础数据类型
  3. POJO
  4. 自定义参数绑定【比如定义转换器Converter
  5. 包装的POJO
  6. 数组:可以绑定到形参上,可以绑定到包装的POJO
  7. 集合:只能保定在包装的POJO

1.2 数组类型的参数的绑定

  • 场景描述:在商品列表页选中多个商品,然后删除。

  • 需求分析:此功能要求列表页中的每个商品前有一个checkbox,选中多个商品点击删除按钮,把此商品的id传递给Controller,根据商品的id删除商品信息。

  • JSP中的实现

JSP代码
  • 程序运行后生成的html代码如下:
查看生成的html源码
  • Controller方法中可以使用String[]接收,或者pojoString[]属性接收。两种方式任选一种即可。
  • 方式一:直接绑定到形参上
@RequestMapping("/queryitem")
    public String queryItem(QueryVo queryVo, String[] ids) {
        System.out.println(queryVo.getItems().getName());
        System.out.println(queryVo.getItems().getPrice());
        System.out.println(ids.toString());
        return null;
    }
  • 方式二:绑定到包装的pojo
绑定到包装的pojo上
  • 查看结果
查看结果

1.3 集合类型的参数的绑定

  • 场景描述:实现商品数据的批量修改。
  • 需求分析:要想实现商品数据的批量删除,需要在商品列表中可以对商品进行修改,并且可以批量提交修改后的商品数据。这时需要将表单的数据绑定到List
  • List中存放对象,并将定义的List放在包装类中,使用包装的pojo对象接收。接收商品列表的pojo如下:
接收商品列表的pojo
  • JSP改造
页面代码
  • Name属性必须是包装pojo的list属性+下标+元素属性。Jsp做如下改造:
JSP改造
varStatus属性常用参数总结下:
${status.index}      输出行号,从0开始。
${status.count}      输出行号,从1开始。
${status.current}   当前这次迭代的(集合中的)项
${status.first}  判断当前项是否为集合中的第一项,返回值为true或false
${status.last}   判断当前项是否为集合中的最后一项,返回值为true或false
begin、end、step分别表示:起始序号,结束序号,跳跃步伐。
  • Controller
@RequestMapping("/queryitem")
    public String queryItem(QueryVo queryVo, String[] ids) {
        System.out.println(queryVo.getItems().getName());
        System.out.println(queryVo.getItems().getPrice());
        System.out.println(ids.toString());
        return null;
    }
  • 接收List类型的数据必须是pojo的属性,方法的形参为List类型无法正确接收到数据。

第2章 @RequestMapping的用法

  1. value={"/list","/list2","/itemList"}多个请求地址可以同时指向同一个方法
  2. method=RequestMethod.GET限制请求方式
  3. @RequestMapping可以写到Controller上 ,窄化请求映射

2.1 URL路径映射

  • @RequestMapping(value="/item")@RequestMapping("/item)value的值是数组,可以将多个url映射到同一个方法。例如:
多个url映射到同一个方法

2.2 请求方法限定

  • 限定GET方式请求:只能以GET方式访问才能通过
@RequestMapping(method = RequestMethod.GET)
//如果通过Post访问则报错:
//HTTP Status 405 - Request method 'POST' not supported

//例如:
@RequestMapping(value="/editItem",method=RequestMethod.GET)
  • 限定POST方法
@RequestMapping(method = RequestMethod.POST)
  • GETPOST都可以都可以访问
@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})

2.3 窄化请求映射

  • class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,通过此方法对url进行分类管理。
  • 例如:
@Controller
@RequestMapping("/items/")
public class ItemsController {

    @Autowired
    private ItemService itemService ;
    
    @RequestMapping(value={"/list","/list2","/itemList"},method={RequestMethod.GET,RequestMethod.POST})
    public ModelAndView showList(QueryVo queryVo,int[] ids){

        List<Items> list = itemService.findAll();
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("itemList", list);
        modelAndView.setViewName("itemList");
        return modelAndView;
    }
  • 访问的地址为:/items/list

第3章 Controller方法的返回类型

  • Controller方法的返回值类型有三种:
    • ModelAndView
    • String
    • void

3.1 返回ModelAndView

  • controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view

3.2 返回void

  • Controller方法的返回值类型为void时,可以在controller方法形参上定义requestresponse,使用requestresponse指定响应结果。
  • 使用request转向页面:
request.getRequestDispatcher("页面路径").forward(request, response);
  • 使用response页面重定向
response.sendRedirect("url")

3.3 返回类型为String

3.3.1 逻辑视图名

  • controller方法返回字符串可以指定逻辑视图名,通过视图解析器解析为物理视图地址。
//指定逻辑视图名,经过视图解析器解析为jsp物理路径:
/WEB-INF/jsp/item/editItem.jsp

return "item/editItem";

3.3.2 重定向

  • Contrller方法返回结果重定向到一个url地址,如下商品修改提交后重定向到商品查询方法,参数无法带到商品查询方法中。
//重定向到list.action地址,request无法带过去
return "redirect:list.action";
  • redirect方式相当于response.sendRedirect(),转发后浏览器的地址栏变为重定向后的地址,因为重定向即执行了一个新的requestresponse

  • 由于新发起一个request原来的参数在转发时就不能传递到下一个url,如果要传参数可以/item/list.action后边加参数,如下:

    /item/list?...&…..
    

3.3.3 转发

  • controller方法执行后继续执行另一个controller方法,如下商品修改提交后转向到商品修改页面,修改商品的id参数可以带到商品修改方法中。
//结果转发到editItem.action,request可以带过去
return "forward:editItem.action";
  • forward方式相当于request.getRequestDispatcher().forward(request,response),转发后浏览器地址栏还是原来的地址。转发并没有执行新的requestresponse,而是和转发前的请求共用一个requestresponse。所以转发前请求的参数在转发后仍然可以读取到。

第4章 文件上传【重要】

4.1 文件上传页面三要素

  1. 表单的提交方式method一定是post
  2. 表单enctype的值一定是multipart/form-data
  3. 文件上传项input的类型一定是file

4.2 SpringMVC上传文件注意点

  1. 需要添加两个jarcommons-io.jarcommons-fileupload.jar
  2. SpringMVC容器中配置文件解析器
  3. 绑定参数类型是MultipartFile,参数的名称要和页面input属性值保持一致。

4.3 开始上传

4.3.1 场景设计

  • 在商品展示页面单击修改按钮后跳转到修改页面
商品展示页面点击修改按钮后跳转
  • 修改页面
修改页面

4.3.2 导入文件上传的jar包

jar包

4.3.3 修改页面的jsp代码

  • WebContent/jsp/editItem.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>

</head>
<body> 
    <!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
    <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
    <form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action"
            enctype="multipart/form-data" method="post">
        <input type="hidden" name="id" value="${item.id }" /> 修改商品信息:
        <table width="100%" border=1>
            <tr>
                <td>商品名称</td>
                <td><input type="text" name="name" value="${item.name }" /></td>
            </tr>
            <tr>
                <td>商品价格</td>
                <td><input type="text" name="price" value="${item.price }" /></td>
            </tr>
            <%-- 
            <tr>
                <td>商品生产日期</td>
                <td><input type="text" name="createtime"
                    value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>" /></td>
            </tr>
            --%>
            <tr>
                <td>商品图片</td>
                <td>
                    <c:if test="${item.pic !=null}">
                        <img src="/pic/${item.pic}" width=100 height=100/>
                        <br/>
                    </c:if>
                    <input type="file"  name="pictureFile"/> 
                </td>
            </tr>
             
            <tr>
                <td>商品简介</td>
                <td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea>
                </td>
            </tr>
            <tr>
                <td colspan="2" align="center"><input type="submit" value="提交" />
                </td>
            </tr>
        </table>

    </form>
</body>
</html>

4.3.4 配置文件 解析器

  • springmvc.xml中添加如下配置:
<!-- 文件上传 -->
    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 设置上传文件的最大尺寸为5MB -->
        <property name="maxUploadSize">
            <value>5242880</value>
        </property>
    </bean>

4.3.5 编写Controller修改商品的方法,其中包括文件上传

// 商品修改
    @RequestMapping("updateitem")
    public String updateitem(Items item, MultipartFile pictureFile,  Model model) throws IllegalStateException, IOException {
        // 获取上传文件的完整名称(带扩展名)
        String originalFilename = pictureFile.getOriginalFilename(); 
        String fileName = UUID.randomUUID().toString(); // 创建一个随机数,作为即将保存图片的名字
        // 获取文件的扩展名
        String ext = originalFilename.substring(originalFilename.lastIndexOf(".")); 
        pictureFile.transferTo(new File("d:\\upload\\"+fileName+ext)); // 文件保存
        item.setPic(fileName+ext);
        itemService.update(item);
        return "redirect:list.action";
    }

4.3.6 测试

  • 在修改页面填写修改信息,点击提交后页面跳转到商品展示页。上传的图片保存到了磁盘上,数据库中对应的记录更新。

4.3.7 注意

  • filenamecontroller的形参保持一致
  • form添加enctype="multipart/form-data"
  • 文件上传的目录需要提前创建好
  • 需要在springmvc.xml中配置文件解析器

第5章 异常处理器

5.1 异常处理的思路

  • Web工程中一般都是三层结构,如果系统中无论那一层发送异常都可以直接向上抛出,而不用处理。如下图所示,系统的daoservicecontroller出现异常后都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理。
异常处理思路

5.2 自定义异常处理器的举例

5.2.1 场景描述

  • 在商品展示修改页面,当用户访问到id不存在的路径时出现异常。
输入id不存在的路径

5.2.2 自定义异常处理器

  • com.itzhouq.ssm.exception.MyHandlerExceptionResolver
package com.itzhouq.ssm.exception;

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

import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
/**
 *  自定义异常处理器
 * @author itzhouq
 *
 */
public class MyHandlerExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object method,
            Exception exception) {
        // 跳转到错误页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("errorMessage", exception.getMessage());
        modelAndView.setViewName("error");
        return modelAndView;
    }

}

5.2.3 编写错误页面

  • WebContent/jsp/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>Insert title here</title>
</head>
<body>
 <h1>由于您的操作造成系统异常,错误信息如下,请转告开发工程师:<br/></h1>
 ${errorMessage }
</body>
</html>

5.2.4 配置异常处理器

  • springmvc.xml中添加以下配置:
<!-- 异常处理器 -->
    <bean id="handlerExceptionResolver" class="com.itzhouq.ssm.exception.MyHandlerExceptionResolver"/>

5.2.5 模拟异常

  • com.itzhouq.ssm.controller.ItemsController
//  展示修改页面
    @RequestMapping("/itemEdit")
    public String itemEdit(@RequestParam(value="id",required=false,defaultValue="1")int itemId,HttpServletRequest request, HttpServletResponse response,Model model){
        Items items = itemService.findById(itemId);
        // 模拟异常
        if(items == null) {
            int i = 1 / 0;
        }
        model.addAttribute("item", items);
//      逻辑视图:jsp的路径
        return "editItem";
    }

5.2.6 测试

  • 访问http://localhost/Spring-mybatis-test/itemEdit.action?id=9id=9是不存在的。
错误页

第6章 JSON数据交互

6.1 场景设计

  • 商品修改页面,修改商品信息后,如果需要使用Ajax的异步提交方式,需要和json交互。

6.2 在修改页面引入JS支持

  • WebContent/jsp/editItem.jsp引入js
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>

6.3 修改提交方式

<input type="button" onclick="save()" value="提交" />

6.4 编写save函数和ajax代码

  • $("#itemForm").serialize()可以将表单数据序列化,将数据封装成对象
<script type="text/javascript">
 function save(){
//   ajax异步提交
// alert($("#itemForm").serialize()); 
     $.ajax({
         url:'${pageContext.request.contextPath }/updateitemAjax.action',
         type:'post',
         data:$("#itemForm").serialize(),
         dataType:'json',
         success:function(data){
//           data :{"success":true|false,"message":"操作成功"|“操作失败”}
             if(data.success){
                location.href="${pageContext.request.contextPath }/list.action";
             }else{
                alert(data.message); 
             }
         } 
     })
 }
</script>

6.5 在Controller中编写updateitemAjax方法

    // 使用Ajax异步提交方式的修改
    @RequestMapping("/updateitemAjax")
    @ResponseBody   // 作用:把即将返回的对象转化json字符串并且写道浏览器
    public Map updateitemAjax(Items item) {
//      data :{"success":true|false,"message":"操作成功"|“操作失败”}
        Map<String,Object> map = new HashMap<String,Object>();
        try {
            itemService.update(item);
            map.put("success", true);
            map.put("message", "操作成功");
        } catch (Exception e) {
            map.put("success", false);
            map.put("message", "操作失败");
//          e.printStackTrace();
        }
        return map;
    }
  • @ResponseBody // 作用:把即将返回的对象转化json字符串并且写道浏览器,这个注解需要引入jar
springmvc引入json支持

6.6 测试

  • 访问http://localhost/Spring-mybatis-test/list.action点击修改按钮后,修改信息,提交后页面跳转,后台数据map中保存了信息{success=true, message=操作成功}

第7章 RESTful支持

7.1 什么是restful风格

  • Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格,是对hhtp协议的诠释。
  • 可以简单理解为精简的url地址:比如http://localhost/Spring-mybatis-test/itemEdit.action?id=2可以访问商品修改页,我现在想让访问的路径精简为http://localhost/Spring-mybatis-test/itemEdit/2

7.2 案例:实现对商品访问页的restful风格支持

7.2.1 实现思路

  1. 修改web.xml中前端控制器<url-pattern>/</url-pattern>的配置
  2. 修改方法的@RequestMapping
  3. 处理静态资源

7.2.2 修改前端控制器配置

  • 之前的前端控制器的配置如下:
<!--   前端控制器 -->
 <servlet>
  <servlet-name>springmvc</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <init-param>
   <param-name>contextConfigLocation</param-name>
   <param-value>classpath:springmvc.xml</param-value>
  </init-param>
 </servlet>
 <servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <url-pattern>*.action</url-pattern>
 </servlet-mapping>
  • 也就说请求的url必须是*.action这样的格式,才会进入前端控制器。需要修改为:
<servlet-mapping>
  <servlet-name>springmvc</servlet-name>
  <!-- / 不包含jsp -->
  <!-- /* 包含jsp -->
  <url-pattern>/</url-pattern>
 </servlet-mapping>

7.2.3 修改Controller方法的@RequestMapping:URL模板映射

  • com.itzhouq.ssm.controller.ItemsController
//  展示修改页面
    @RequestMapping("/itemEdit/{id}")
    public String itemEdit(@PathVariable("id")int itemId,HttpServletRequest request, HttpServletResponse response,Model model){
        Items items = itemService.findById(itemId);
        model.addAttribute("item", items);
//      逻辑视图:jsp的路径
        return "editItem";
    }
  • 到了这一步就可以通过精简的路径访问了。
通过精简的路径访问
  • 但是控制台提示找不到js。这是由于我们配置前端控制的时候<url-pattern>/</url-pattern>使用的是/,也就是除jsp外的所有请求都会进入springmvc容器中,进而去控制器中寻找响应的方法,但是没有方法映射静态资源,所以就报404。
  • 所以现在要处理静态资源,让静态资源去Webcontent下寻找资源而不是进入springmvc容器中。

7.2.4 处理静态资源访问

  • springmvc.xml中配置
<!-- 配置静态资源 -->
<!-- location:请求地址   mapping:映射的位置 -->
<mvc:resources location="/js/" mapping="/js/**"></mvc:resources>

第8章 拦截器

8.1 SpringMVC的拦截器

  • SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。

8.2 拦截器的定义

  • 定义拦截器要实现接口HandlerInterceptor

  • com.itzhouq.ssm.interceptor.MyHandlerInterceptor1

public class MyHandlerInterceptor1 implements HandlerInterceptor {
    /**
     * controller执行前调用此方法
     * 返回true表示继续执行,返回false中止执行
     * 这里可以加入登录校验、权限拦截等
     */
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("执行了MyHandlerInterceptor1的前置方法");
        return true;
    }

    /**
     * controller执行后但未返回视图前调用此方法
     * 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
     */
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("执行了MyHandlerInterceptor1的执行方法");
    }

    /**
     * controller执行后且视图返回后调用此方法
     * 这里可得到执行controller时的异常信息
     * 这里可记录操作日志,资源清理等
     */
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("执行了MyHandlerInterceptor1的后置方法");
    }
}
  • com.itzhouq.ssm.interceptor.MyHandlerInterceptor2
public class MyHandlerInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("执行了MyHandlerInterceptor2的前置方法");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("执行了MyHandlerInterceptor2的执行方法");
    }
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("执行了MyHandlerInterceptor2的后置方法");
    }
}

8.3 拦截器配置

8.3.1 针对所有mapping配置全局拦截器

  • springmvc.xml中添加配置
<!-- 针对所有mapping配置全局拦截器 /**表示所有的拦截器都可以进入 -->
<mvc:interceptors>
    <!-- 多个拦截器按照顺序执行 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.itzhouq.ssm.interceptor.MyHandlerInterceptor1"/>
    </mvc:interceptor>

    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.itzhouq.ssm.interceptor.MyHandlerInterceptor2"/>
    </mvc:interceptor>
</mvc:interceptors>

8.3.2 针对某种mapping配置拦截器

  • 参考代码
<bean
    class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    <property name="interceptors">
        <list>
            <ref bean="handlerInterceptor1"/>
            <ref bean="handlerInterceptor2"/>
        </list>
    </property>
</bean>
    <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/>
    <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>

8.4 测试

  • 访问http://localhost/Spring-mybatis-test/itemEdit/2,查看后台拦截器的执行顺序
执行了MyHandlerInterceptor1的前置方法
执行了MyHandlerInterceptor2的前置方法

执行了MyHandlerInterceptor2的执行方法
执行了MyHandlerInterceptor1的执行方法

执行了MyHandlerInterceptor2的后置方法
执行了MyHandlerInterceptor1的后置方法


总结:
preHandle按拦截器定义顺序调用
postHandler按拦截器定义逆序调用
afterCompletion按拦截器定义逆序调用

postHandler在拦截器链内所有拦截器返成功调用
afterCompletion只有preHandle返回true才调用

8.5 拦截器的应用

8.5.1 用户身份认证

Public class LoginInterceptor implements HandlerInterceptor{

    @Override
    Public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        //如果是登录页面则放行
        if(request.getRequestURI().indexOf("login.action")>=0){
            return true;
        }
        HttpSession session = request.getSession();
        //如果用户已登录也放行
        if(session.getAttribute("user")!=null){
            return true;
        }
        //用户没有登录挑战到登录页面
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        
        return false;
    }
}

8.5.2 用户登录Controller

//登陆页面
    @RequestMapping("/login")
    public String login(Model model)throws Exception{
        
        return "login";
    }
    
    //登陆提交
    //userid:用户账号,pwd:密码
    @RequestMapping("/loginsubmit")
    public String loginsubmit(HttpSession session,String userid,String pwd)throws Exception{
        
        //向session记录用户身份信息
        session.setAttribute("activeUser", userid);
        
        return "redirect:item/queryItem.action";
    }
    
    //退出
    @RequestMapping("/logout")
    public String logout(HttpSession session)throws Exception{
        
        //session过期
        session.invalidate();
        
        return "redirect:item/queryItem.action";
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容