SpringMVC執(zhí)行流程及工作原理

圖解SpringMVC執(zhí)行流程:

SpringMVC執(zhí)行流程

SpringMVC執(zhí)行流程:
1.用戶發(fā)送請(qǐng)求至前端控制器DispatcherServlet
2.DispatcherServlet收到請(qǐng)求調(diào)用處理器映射器HandlerMapping伤锚。
3.處理器映射器根據(jù)請(qǐng)求url找到具體的處理器尊勿,生成處理器執(zhí)行鏈HandlerExecutionChain(包括處理器對(duì)象和處理器攔截器)一并返回給DispatcherServlet唐瀑。
4.DispatcherServlet根據(jù)處理器Handler獲取處理器適配器HandlerAdapter執(zhí)行HandlerAdapter處理一系列的操作徒恋,如:參數(shù)封裝辕近,數(shù)據(jù)格式轉(zhuǎn)換,數(shù)據(jù)驗(yàn)證等操作
5.執(zhí)行處理器Handler(Controller迹冤,也叫頁面控制器)讽营。
6.Handler執(zhí)行完成返回ModelAndView
7.HandlerAdapter將Handler執(zhí)行結(jié)果ModelAndView返回到DispatcherServlet
8.DispatcherServlet將ModelAndView傳給ViewReslover視圖解析器
9.ViewReslover解析后返回具體View
10.DispatcherServlet對(duì)View進(jìn)行渲染視圖(即將模型數(shù)據(jù)model填充至視圖中)。
11.DispatcherServlet響應(yīng)用戶泡徙。

當(dāng)然也有以下幾種表示但是都是與第一種說法一樣.

執(zhí)行流程

我們針對(duì)第一張圖進(jìn)行分析

組件說明:

1.DispatcherServlet:前端控制器橱鹏。用戶請(qǐng)求到達(dá)前端控制器,它就相當(dāng)于mvc模式中的c堪藐,dispatcherServlet是整個(gè)流程控制的中心莉兰,由它調(diào)用其它組件處理用戶的請(qǐng)求,dispatcherServlet的存在降低了組件之間的耦合性,系統(tǒng)擴(kuò)展性提高礁竞。由框架實(shí)現(xiàn)
2.HandlerMapping:處理器映射器糖荒。HandlerMapping負(fù)責(zé)根據(jù)用戶請(qǐng)求的url找到Handler即處理器,springmvc提供了不同的映射器實(shí)現(xiàn)不同的映射方式模捂,根據(jù)一定的規(guī)則去查找,例如:xml配置方式捶朵,實(shí)現(xiàn)接口方式蜘矢,注解方式等。由框架實(shí)現(xiàn)
3.Handler:處理器综看。Handler 是繼DispatcherServlet前端控制器的后端控制器品腹,在DispatcherServlet的控制下Handler對(duì)具體的用戶請(qǐng)求進(jìn)行處理。由于Handler涉及到具體的用戶業(yè)務(wù)請(qǐng)求红碑,所以一般情況需要程序員根據(jù)業(yè)務(wù)需求開發(fā)Handler舞吭。
4.HandlAdapter:處理器適配器。通過HandlerAdapter對(duì)處理器進(jìn)行執(zhí)行析珊,這是適配器模式的應(yīng)用羡鸥,通過擴(kuò)展適配器可以對(duì)更多類型的處理器進(jìn)行執(zhí)行。由框架實(shí)現(xiàn)忠寻。
5.ModelAndView是springmvc的封裝對(duì)象兄春,將model和view封裝在一起。
6.ViewResolver:視圖解析器锡溯。ViewResolver負(fù)責(zé)將處理結(jié)果生成View視圖,ViewResolver首先根據(jù)邏輯視圖名解析成物理視圖名即具體的頁面地址哑姚,再生成View視圖對(duì)象祭饭,最后對(duì)View進(jìn)行渲染將處理結(jié)果通過頁面展示給用戶。
7View:是springmvc的封裝對(duì)象叙量,是一個(gè)接口, springmvc框架提供了很多的View視圖類型倡蝙,包括:jspview,pdfview,jstlView绞佩、freemarkerView寺鸥、pdfView等。一般情況下需要通過頁面標(biāo)簽或頁面模版技術(shù)將模型數(shù)據(jù)通過頁面展示給用戶品山,需要由程序員根據(jù)業(yè)務(wù)需求開發(fā)具體的頁面胆建。

執(zhí)行流程對(duì)應(yīng)的代碼
1.請(qǐng)求到達(dá)前端控制器的第一站,先做些準(zhǔn)備工作

/**
 * Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
 * for the actual dispatching.
 */
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
   if (logger.isDebugEnabled()) {
      String requestUri = urlPathHelper.getRequestUri(request);
      logger.debug("DispatcherServlet with name '" + getServletName() + "' processing " + request.getMethod() +
            " request for [" + requestUri + "]");
   }

    //保護(hù)現(xiàn)場(chǎng)
   // Keep a snapshot of the request attributes in case of an include,
   // to be able to restore the original attributes after the include.
   Map<String, Object> attributesSnapshot = null;
   if (WebUtils.isIncludeRequest(request)) {
      logger.debug("Taking snapshot of request attributes before include");
      attributesSnapshot = new HashMap<String, Object>();
      Enumeration<?> attrNames = request.getAttributeNames();
      while (attrNames.hasMoreElements()) {
         String attrName = (String) attrNames.nextElement();
         if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
            attributesSnapshot.put(attrName, request.getAttribute(attrName));
         }
      }
   }

    //將框架相關(guān)信息存儲(chǔ)至request肘交,方便后面的處理器和視圖用到
   // Make framework objects available to handlers and view objects.
   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
   if (inputFlashMap != null) {
      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
   }
   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

    //請(qǐng)求分發(fā)
   try {
      doDispatch(request, response);
   }
   finally {
      // Restore the original attribute snapshot, in case of an include.
      if (attributesSnapshot != null) {
         restoreAttributesAfterInclude(request, attributesSnapshot);
      }
   }
}

2.開始處理請(qǐng)求
//通過url查找HandlerMap中最相近的key(url)笆载,然后由key獲取HandlerMapping對(duì)象
//通過處理器映射器獲取處理器;
//通過查詢處理器適配器獲得

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   int interceptorIndex = -1;

   try {
      ModelAndView mv;
      boolean errorView = false;

      try {
         processedRequest = checkMultipart(request);

         // Determine handler for the current request
        //步驟3.1~3.4用于獲取包含處理器Handler和攔截器AdapterIntercepters的處理器執(zhí)行鏈HandlerExecutionChain
         mappedHandler = getHandler(processedRequest, false);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
        //步驟4.1~4.2,根據(jù)HandlerExecutionChain中的處理器Handler獲取處理器適配器
         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

               // Process last-modified header, if supported by the handler.
         String method = request.getMethod();
         boolean isGet = "GET".equals(method);
         if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (logger.isDebugEnabled()) {
               String requestUri = urlPathHelper.getRequestUri(request);
               logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
            }
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
               return;
            }
         }

         // Apply preHandle methods of registered interceptors.
         HandlerInterceptor[] interceptors = mappedHandler.getInterceptors();
         if (interceptors != null) {
            for (int i = 0; i < interceptors.length; i++) {
               HandlerInterceptor interceptor = interceptors[i];
               if (!interceptor.preHandle(processedRequest, response, mappedHandler.getHandler())) {
                  triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
                  return;
               }
               interceptorIndex = i;
            }
         }

         // Actually invoke the handler.
        //5.1~5.3通過處理器適配器HandlerApapter來調(diào)用處理器完成對(duì)請(qǐng)求的處理
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         // Do we need view name translation?
         if (mv != null && !mv.hasView()) {
            mv.setViewName(getDefaultViewName(request));
         }

         // Apply postHandle methods of registered interceptors.
         if (interceptors != null) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
               HandlerInterceptor interceptor = interceptors[i];
               interceptor.postHandle(processedRequest, response, mappedHandler.getHandler(), mv);
            }
         }
      }
      catch (ModelAndViewDefiningException ex) {
         logger.debug("ModelAndViewDefiningException encountered", ex);
         mv = ex.getModelAndView();
      }
      catch (Exception ex) {
         Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
         mv = processHandlerException(processedRequest, response, handler, ex);
         errorView = (mv != null);
      }

      // Did the handler return a view to render?
      if (mv != null && !mv.wasCleared()) {
         render(mv, processedRequest, response);
         if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
         }
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                  "': assuming HandlerAdapter completed request handling");
         }
      }

      // Trigger after-completion for successful outcome.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, null);
   }

   catch (Exception ex) {
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }
   catch (Error err) {
      ServletException ex = new NestedServletException("Handler processing failed", err);
      // Trigger after-completion for thrown exception.
      triggerAfterCompletion(mappedHandler, interceptorIndex, processedRequest, response, ex);
      throw ex;
   }

   finally {
      // Clean up any resources used by a multipart request.
      if (processedRequest != request) {
         cleanupMultipart(processedRequest);
      }
   }
}

3.1 getHandler(HttpServletRequest request)涯呻,經(jīng)由HandlerMapping對(duì)象獲取HandlerExecutionChain(處理器和攔截器)

/**
 * Return the HandlerExecutionChain for this request.
 * <p>Tries all handler mappings in order.
 * @param request current HTTP request
 * @return the HandlerExecutionChain, or <code>null</code> if no handler could be found
 */
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      if (logger.isTraceEnabled()) {
         logger.trace(
               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
      }
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}

3.2.1 getHandler(HttpServletRequest request)凉驻,經(jīng)由request獲取處理器,獲取處理器Handler后复罐,再獲取攔截器涝登,最后組成HandlerExecutionChain

/**
 * Look up a handler for the given request, falling back to the default
 * handler if no specific one is found.
 * @param request current HTTP request
 * @return the corresponding handler instance, or the default handler
 * @see #getHandlerInternal
 */
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }
   return getHandlerExecutionChain(handler, request);
}

3.2.2 根據(jù)查找到的處理器Handler和request獲取包含Handler和AdaptedInterceptors的HandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
   HandlerExecutionChain chain = 
      (handler instanceof HandlerExecutionChain) ?
         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);

   chain.addInterceptors(getAdaptedInterceptors());

   String lookupPath = urlPathHelper.getLookupPathForRequest(request);
   for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
      if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
         chain.addInterceptor(mappedInterceptor.getInterceptor());
      }
   }

   return chain;
}
/**
 * Return the adapted interceptors as HandlerInterceptor array.
 * @return the array of HandlerInterceptors, or <code>null</code> if none
 */
protected final HandlerInterceptor[] getAdaptedInterceptors() {
   int count = adaptedInterceptors.size();
   return (count > 0) ? adaptedInterceptors.toArray(new HandlerInterceptor[count]) : null;
}

3.3.getHandlerInternal(HttpServletRequest request)獲取Handler

/**
 * Look up a handler for the URL path of the given request.
 * @param request current HTTP request
 * @return the handler instance, or <code>null</code> if none found
 */
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   Object handler = lookupHandler(lookupPath, request);
   if (handler == null) {
      // We need to care for the default handler directly, since we need to
      // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
      Object rawHandler = null;
      if ("/".equals(lookupPath)) {
         rawHandler = getRootHandler();
      }
      if (rawHandler == null) {
         rawHandler = getDefaultHandler();
      }
      if (rawHandler != null) {
         // Bean name or resolved handler?
         if (rawHandler instanceof String) {
            String handlerName = (String) rawHandler;
            rawHandler = getApplicationContext().getBean(handlerName);
         }
         validateHandler(rawHandler, request);
         handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
      }
   }
   if (handler != null && logger.isDebugEnabled()) {
      logger.debug("Mapping [" + lookupPath + "] to " + handler);
   }
   else if (handler == null && logger.isTraceEnabled()) {
      logger.trace("No handler mapping found for [" + lookupPath + "]");
   }
   return handler;
}

3.4 lookupHandler(lookupPath, request)根據(jù)給定url path和request獲取Handler

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
   // Direct match?
   Object handler = this.handlerMap.get(urlPath);
   if (handler != null) {
      // Bean name or resolved handler?
      if (handler instanceof String) {
         String handlerName = (String) handler;
         handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      return buildPathExposingHandler(handler, urlPath, urlPath, null);
   }
   // Pattern match?
   List<String> matchingPatterns = new ArrayList<String>();
   for (String registeredPattern : this.handlerMap.keySet()) {
      if (getPathMatcher().match(registeredPattern, urlPath)) {
         matchingPatterns.add(registeredPattern);
      }
   }
   String bestPatternMatch = null;
   Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
   if (!matchingPatterns.isEmpty()) {
      Collections.sort(matchingPatterns, patternComparator);
      if (logger.isDebugEnabled()) {
         logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
      }
      bestPatternMatch = matchingPatterns.get(0);
   }
   if (bestPatternMatch != null) {
      handler = this.handlerMap.get(bestPatternMatch);
      // Bean name or resolved handler?
      if (handler instanceof String) {
         String handlerName = (String) handler;
         handler = getApplicationContext().getBean(handlerName);
      }
      validateHandler(handler, request);
      String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);

      // There might be multiple 'best patterns', let's make sure we have the correct URI template variables
      // for all of them
      Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
      for (String matchingPattern : matchingPatterns) {
         if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
            uriTemplateVariables
                  .putAll(getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath));
         }
      }
      if (logger.isDebugEnabled()) {
         logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);
      }
      return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
   }
   // No handler found...
   return null;
}

4.1 HandlerAdapter getHandlerAdapter(Object handler),根據(jù)Handler獲取HandlerAdapter

/**
 * Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
   for (HandlerAdapter ha : this.handlerAdapters) {
      if (logger.isTraceEnabled()) {
         logger.trace("Testing handler adapter [" + ha + "]");
      }
      if (ha.supports(handler)) {
         return ha;
      }
   }
   throw new ServletException("No adapter for handler [" + handler +
         "]: Does your handler implement a supported interface like Controller?");
}

4.2 supports(Object handler)

public boolean supports(Object handler) {
   return (handler instanceof Controller);
}

5.1 使用處理器完成對(duì)請(qǐng)求的處理

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {

   ((Servlet) handler).service(request, response);
   return null;
}
public void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException
{
    HttpServletRequest  request;
    HttpServletResponse response;

    if (!(req instanceof HttpServletRequest &&
            res instanceof HttpServletResponse)) {
        throw new ServletException("non-HTTP request or response");
    }

    request = (HttpServletRequest) req;
    response = (HttpServletResponse) res;

    service(request, response);
}

5.2 service(HttpServletRequest req, HttpServletResponse resp)

protected void service(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    String method = req.getMethod();

    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < lastModified) {
                // If the servlet mod time is later, call doGet()
                // Round down to the nearest second for a proper compare
                // A ifModifiedSince of -1 will always be less
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);

    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

5.3 doGet(HttpServletRequest req, HttpServletResponse resp)

protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    String protocol = req.getProtocol();
    String msg = lStrings.getString("http.method_get_not_supported");
    if (protocol.endsWith("1.1")) {
        resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
    } else {
        resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
    }
}

點(diǎn)擊查看-->SpringMVC開發(fā)流程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末效诅,一起剝皮案震驚了整個(gè)濱河市胀滚,隨后出現(xiàn)的幾起案子趟济,更是在濱河造成了極大的恐慌,老刑警劉巖蛛淋,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件咙好,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡褐荷,警方通過查閱死者的電腦和手機(jī)勾效,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叛甫,“玉大人层宫,你說我怎么就攤上這事∑浼啵” “怎么了萌腿?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長抖苦。 經(jīng)常有香客問我毁菱,道長,這世上最難降的妖魔是什么锌历? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任贮庞,我火速辦了婚禮,結(jié)果婚禮上究西,老公的妹妹穿的比我還像新娘窗慎。我一直安慰自己,他們只是感情好卤材,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布遮斥。 她就那樣靜靜地躺著,像睡著了一般扇丛。 火紅的嫁衣襯著肌膚如雪术吗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天晕拆,我揣著相機(jī)與錄音藐翎,去河邊找鬼。 笑死实幕,一個(gè)胖子當(dāng)著我的面吹牛吝镣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昆庇,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼末贾,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了整吆?” 一聲冷哼從身側(cè)響起拱撵,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤辉川,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后拴测,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乓旗,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年集索,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了屿愚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡务荆,死狀恐怖妆距,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情函匕,我是刑警寧澤娱据,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站盅惜,受9級(jí)特大地震影響中剩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抒寂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一咽安、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蓬推,春花似錦、人聲如沸澡腾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽动分。三九已至毅糟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澜公,已是汗流浹背姆另。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坟乾,地道東北人迹辐。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像甚侣,于是被迫代替她去往敵國和親明吩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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