国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring之旅第八站:Spring MVC Spittr舞臺的搭建、基本的控制器、請求的輸入、表

maybe_009 / 3672人閱讀

摘要:請求旅程的第一站是的。的任務(wù)是將請求發(fā)送控制器控制器是一個用于處理請求的組件。處理映射器根據(jù)請求攜帶的信息來進(jìn)行決策。這樣的結(jié)果就是,只能找到顯示聲明在配置類中的控制器。

構(gòu)建Spring Web應(yīng)用 說明

如果你有幸能看到。

1、本文參考了《Spring 實戰(zhàn)》重點內(nèi)容,參考了GitHub上的代碼

2、本文只為記錄作為以后參考,要想真正領(lǐng)悟Spring的強大,請看原書。

3、在一次佩服老外,國外翻譯過來的書,在GiuHub上大都有實例。看書的時候,跟著敲一遍,效果很好。

4、代碼和筆記在這里GitHub,對你有幫助的話,歡迎點贊。

5、每個人的學(xué)習(xí)方式不一樣,找到合適自己的就行。2018,加油。

6、Java 8 In Action 的作者M(jìn)ario Fusco

7、Spring In Action 、Spring Boot In Action的作者Craig Walls

8、知其然,也要知其所以然。

談一些個人感受

1、趕快學(xué)習(xí)Spring吧,Spring MVC 、Spring Boot 、微服務(wù)。

2、重點中的重點,學(xué)習(xí)JDK 8 Lambda,Stream,Spring 5 最低要求JDK1.8.

3、還有Netty、放棄SH吧,不然你會落伍的。

4、多看一些國外翻譯過來的書,例如 Xxx In Action 系列。權(quán)威指南系列。用Kindle~

5、寫代碼之前先寫測試,這就是老外不同之處。學(xué)到了很多技巧。

系統(tǒng)面臨的挑戰(zhàn):狀態(tài)管理、工作流、以及驗證都是需要解決的重要特性。HTTP協(xié)議的無狀態(tài)決定了這些問題都不是那么容易解決。

Spring的Web框架就是為了幫你解決這些關(guān)注點而設(shè)計的。Spring MVC基于模型-視圖-控制器(Model-View-Controller MVC)模式實現(xiàn)的,他能夠幫你構(gòu)建向Spring框架那樣靈活和松耦合的Web應(yīng)用程序。

在本章中,將會介紹Spring MVC Web框架,并使用新的Spring MVC注解來構(gòu)建處理各種Web請求、參數(shù)、和表單輸入的控制器。

5.1 Spring MVC起步

Spring將請求在調(diào)度Servlet、處理器映射(Handler Mappering)、控制器以及視圖解析器(View resolver)之間移動,每一個Spring MVC中的組件都有特定的目的,并且也沒那么復(fù)雜。

讓我們看一下,請求是如何從客戶端發(fā)起,經(jīng)過Spring MVC中的組件,最終返回到客戶端

5.1.1 跟蹤Spring MVC

每當(dāng)用戶在Web瀏覽器中點擊鏈接或提交表單的時候,請求就開始工作了。請求是一個十分繁忙的家伙,從離開瀏覽器開始到獲取響應(yīng)返回,它會經(jīng)歷很多站,在每站都會留下一些信息,同時也會帶上一些信息。

Spring工作流程描述原文在這里

用戶向服務(wù)器發(fā)送請求,請求被Spring 前端控制Servelt DispatcherServlet捕獲;

DispatcherServlet對請求URL進(jìn)行解析,得到請求資源標(biāo)識符(URI)。然后根據(jù)該URI,調(diào)用HandlerMapping獲得該Handler配置的所有相關(guān)的對象(包括Handler對象以及Handler對象對應(yīng)的攔截器),最后以HandlerExecutionChain對象的形式返回;

DispatcherServlet 根據(jù)獲得的Handler,選擇一個合適的HandlerAdapter。(附注:如果成功獲得HandlerAdapter后,此時將開始執(zhí)行攔截器的preHandler(...)方法)

提取Request中的模型數(shù)據(jù),填充Handler入?yún)?,開始執(zhí)行Handler(Controller)。 在填充Handler的入?yún)⑦^程中,根據(jù)你的配置,Spring將幫你做一些額外的工作:

HttpMessageConveter: 將請求消息(如Json、xml等數(shù)據(jù))轉(zhuǎn)換成一個對象,將對象轉(zhuǎn)換為指定的響應(yīng)信息

數(shù)據(jù)轉(zhuǎn)換:對請求消息進(jìn)行數(shù)據(jù)轉(zhuǎn)換。如String轉(zhuǎn)換成Integer、Double等

數(shù)據(jù)根式化:對請求消息進(jìn)行數(shù)據(jù)格式化。 如將字符串轉(zhuǎn)換成格式化數(shù)字或格式化日期等

數(shù)據(jù)驗證: 驗證數(shù)據(jù)的有效性(長度、格式等),驗證結(jié)果存儲到BindingResult或Error中

Handler執(zhí)行完成后,向DispatcherServlet 返回一個ModelAndView對象;

根據(jù)返回的ModelAndView,選擇一個適合的ViewResolver(必須是已經(jīng)注冊到Spring容器中的ViewResolver)返回給DispatcherServlet ;

ViewResolver 結(jié)合Model和View,來渲染視圖

將渲染結(jié)果返回給客戶端。

圖片參考這里

Spring工作流程描述

為什么Spring只使用一個Servlet(DispatcherServlet)來處理所有請求?

詳細(xì)見J2EE設(shè)計模式-前端控制模式

Spring為什么要結(jié)合使用HandlerMapping以及HandlerAdapter來處理Handler?

符合面向?qū)ο笾械膯我宦氊?zé)原則,代碼架構(gòu)清晰,便于維護(hù),最重要的是代碼可復(fù)用性高。如HandlerAdapter可能會被用于處理多種Handler。

1、請求旅程的第一站是Spring的DispatcherServlet。與大多數(shù)基于Java的Web框架一樣,Spring MVC所有的請求都會通過一個前端控制器(front contrller)Servlet.前端控制器是常用Web應(yīng)用程序模式。在這里一個單實例的Servlet將請求委托給應(yīng)用的其他組件來執(zhí)行實際的處理。在Spring MVC中,DisPatcherServlet就是前端控制器。

2、DisPactcher的任務(wù)是將請求發(fā)送Spring MVC控制器(controller).控制器是一個用于處理請求的Spring組件。在典型的應(yīng)用中可能會有多個控制器,DispatcherServlet需要知道應(yīng)該將請求發(fā)送給那個哪個控制器。所以Dispactcher以會查詢一個或 多個處理器映射(Handler mapping),來確定請求的下一站在哪里。處理映射器根據(jù)請求攜帶的 URL信息來進(jìn)行決策。

3、一旦選擇了合適的控制器,DispatcherServlet會將請求發(fā)送給選中的控制器。到了控制器,請求會卸下其負(fù)載(用戶提交的信息)并耐心等待控制器處理這些信息。(實際上,設(shè)計良好的控制器 本身只是處理很少,甚至不處理工作,而是將業(yè)務(wù)邏輯委托給一個或多個服務(wù)器對象進(jìn)行處理)

4、控制器在完成處理邏輯后,通常會產(chǎn)生一些信息。這些 信息需要返回給 用戶,并在瀏覽器上顯示。這些信息被稱為模型(Model),不過僅僅給用戶返回原始的信息是不夠的----這些信息需要以用戶友好的方式進(jìn)行格式化,一般會是HTML。所以,信息需要發(fā)送一個視圖(View),通常會是JSP。

5、 控制器做的最后一件事就是將模型打包,并且表示出用于渲染輸出的視圖名。它接下來會將請求連同模型和視圖發(fā)送回DispatcherServlet。

6、這樣,控制器就不會與特定的視圖相耦合*傳遞給控制器的視圖名并不直接表示某個特定的jsp。實際上,它甚至并不能確定視圖就是JSP。相反,它僅僅傳遞了一個邏輯名稱,這個名字將會用來查找產(chǎn)生結(jié)果的真正視圖。DispatcherServlet將會使用視圖解析器(View resolver),來將邏輯視圖名稱匹配為一個特定的視圖實現(xiàn),他可能也可能不是JSP

7、雖然DispatcherServlet已經(jīng)知道了哪個駛?cè)脘秩窘Y(jié)果、那請求的任務(wù)基本上也就完成了,它的最后一站是試圖的實現(xiàn)。在這里它交付給模型數(shù)據(jù)。請求的任務(wù)就結(jié)束了。視圖將使用模型數(shù)據(jù)渲染輸出。這個輸出通過響應(yīng)對象傳遞給客戶端(不會像聽上去那樣硬編碼)

可以看到,請求要經(jīng)過很多步驟,最終才能形成返回給客戶端的響應(yīng),大多數(shù)的 步驟都是在Spirng框架內(nèi)部完成的。

5.1.2 搭建Spring MVC

借助于最近幾個Spring新特性的功能增強,開始使用SpringMVC變得非常簡單了。使用最簡單的方式配置Spring MVC;所要實現(xiàn)的功能僅限于運行我們所創(chuàng)建的控制器。

配置DisPatcherServlet

DispatcherServlet是Spirng MVC的核心,在這里請求會第一次接觸到框架,它要負(fù)責(zé)將請求路由到其他組件之中。

按照傳統(tǒng)的方式,像DispatcherServlet這樣的Servlet會配置在web.xml中。這個文件會放到應(yīng)用的war包中。當(dāng)然這是配置DispatcherServlet方法之一。借助于Servlet 3規(guī)范和Spring 3.1 的功能增強,這種方式已經(jīng)不是唯一的方案來。

我們會使用Java將DispatcherServlet配置在Servlet容器中。而不會在使用web.xml文件

public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected String[] getServletMappings() {             //將DispatcherServlet映射到“/”
        return new String[]{"/"};
    }

    @Override
    protected Class[] getRootConfigClasses() {
        return new Class [] {RootConfig.class};
    }

    @Override
    protected Class[] getServletConfigClasses() {
        return new Class [] { WebConfig.class};
    }
}

我們只需要知道擴(kuò)展AbstractAnnotationConfigDispatcherServletInitializer的任意類都會自動的配置Dispatcherservlet和Spring應(yīng)用上下文,Spirng的應(yīng)用上下文會位于應(yīng)用程序的Servlet上下文之中

在Servlet3.0環(huán)境中,容器會在類路徑中 查找實現(xiàn)javax.servlet.ServletContainerInitialzer接口的類,如果能發(fā)現(xiàn)的話,就會用它來配置Servlet容器。

Spring提供了這個接口的實現(xiàn)名為SpringServletContainnerInitialzer,這個類反過來又會查找實現(xiàn)WebApplicationInitialzer的類,并將配置的任務(wù)交給他們來完成。Spring 3.2引入了一個遍歷的WebApplicationInitialzer基礎(chǔ)實現(xiàn)也就是AbstractAnnotationConfigDispatcherServletInitializer因為我們的Spittr-WebApplicationInitialzer擴(kuò)展了AbstractAnnotationConfigDispatcherServletInitializer,(同時也就實現(xiàn)了WebApplicationInitialzer),因此當(dāng)部署Servlet3.0容器的時候,容器會自動發(fā)現(xiàn)它,并用它來配置Servlet上下文

第一個方法getServletMappings(),它會將一個或多個路徑映射到DispatcherServlet上,在本示例中,它映射的是“/”,表示它是應(yīng)用默認(rèn)的Servlet,它會處理應(yīng)用的所有請求。

為了理解其他兩個方法,我們首先需要理解DispatcherServlet和一個Servlet監(jiān)聽器(也就是ContextLoaderListener)的關(guān)系。

當(dāng)DispatcherServlet啟動的時候,它會創(chuàng)建應(yīng)用上下文,并加載配置文件或配置類中聲明的bean。在上面那個程序中的getServletConfigClasses()方法中,我們要求DispatcherServlet加載應(yīng)用上下文時,使用定義在WebConfig配置類(使用Java配置)中的bean

但在Spring Web應(yīng)用中,通常還會有另外一個應(yīng)用上下文。另外這個就是由ContextLoaderListener創(chuàng)建.

我們希望DispatcherServlet加載包含Web組件的bean,如控制器,視圖解析器,以及處理器映射,而ContextLoaderListener要加載應(yīng)用中的其他bean。這些bean通常 是驅(qū)動應(yīng)用后端的中間層和數(shù)據(jù)層組件。

實際上AbstractAnnotationConfigDispatcherServletInitializer會同時創(chuàng)建DispatcherServletContextLoaderListener。getServletConfigClasses()方法會返回帶有@Configuration注解的類將會用來定義DispatcherSerle應(yīng)用上下文中的bean,getRootConfigClasses()會返回帶有@Configuration注解的類將會用來配置ContextLoaderListener創(chuàng)建的應(yīng)用上下文。

如果有必要兩個可以同時存在,wex.xml和 AbstractAnnotationConfigDispatcherServletInitializer,但其實沒有必要。

如果按照這種方式配置DispatcherServlet,而不是使用Web.xml的話,那么唯一的問題在于它能部署到支持Servlet3.0的服務(wù)器上才可以正常工作,如Tomcat7或更高版本,Servlet3.0規(guī)范在2009年12月份就發(fā)布了,

如果沒有支持Servlet3.0,那別無選擇了,只能使用web.xml配置類。

啟用Spring MVC

我們有多種方式來啟動DispatcherServlet,與之類似,啟用Spring MVC組件的方式也不止一種,以前Spring是XMl進(jìn)行配置的,你可以選擇啟用注解驅(qū)動的Spring MVC。

在第七章的時候會介紹,現(xiàn)在會讓Spring MVC搭建的過程盡可能簡單,并基于Java進(jìn)行配置。

我們所能創(chuàng)建最簡單的Spring MVC配置就是一個帶有@EnableWebMvc注解的類

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
public class WebConfig {
}

這可以運行起來,它的確能夠啟用Spring MVC,但還有不少問題要解決。

1、沒有配置視圖解析器,如果這樣的話,Spring默認(rèn)會使用BeanNameView-Resolver,這個視圖解析器會查找ID與視圖名稱匹配的bean,并且查找的bean要實現(xiàn)View接口,它以這樣的方式來解析視圖。

2、沒有啟用組件掃描。這樣的結(jié)果就是,Spirng只能找到顯示聲明在配置類中的控制器。

3、這樣配置的話,DispatcherServlet會映射為默認(rèn)的Servlet,所以他會處理所有的請求,包括對靜態(tài)資源的請求,如圖片 和樣式表(在大多數(shù)情況下,這可能并不是你想要的結(jié)果)。

因此我們需要在WebConfig這個最小的Spring MVC配置上再加一些內(nèi)容,從而讓他變得真正實用。

@Configuration
@EnableWebMvc                           //啟用Spring MVC
@ComponentScan("com.guo.spittr.web")    //啟用組件掃描
public class WebConfig extends WebMvcConfigurerAdapter {
    @Bean
    public ViewResolver viewResolver () {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        //配置JSP視圖解析器
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setExposeContextBeansAsAttributes(true);
        return resolver;
    }

    @Override
    //我們要求DispatcherServlet將靜態(tài)資源的請求轉(zhuǎn)發(fā)到Servlet容器中默認(rèn)的Servlet上,
    //而不是使用DispatcherServlet本來來處理此類請求。
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        //配置靜態(tài)資源的處理
        configurer.enable();
    }
}

第一件需要注意的是WebConfig現(xiàn)在添加了@ComponentScan注解,此時將會掃描com.guo.spittr.web包來查找組件。稍后你會看到,我們編寫的控制器將會帶有@Controller注解,這會使其成為組件掃描時的候選bean。因此,我們不需要在配置類中顯示聲明任何的控制器。

接下來,我們添加了一個ViewResolver bean,更具體的將是InternalResourceViewResolver。將會在第6章更為詳細(xì)的討論視圖解析器。我們只需要知道他會去查找jsp文件,在查找的時候,它會在視圖名稱上加一個特定的前綴和后綴。(例如:名為home的視圖會被解析為/WEB-INF/views/home.jsp)

最后新的WebConfig類還擴(kuò)展里WebMvcConfigurerAdapter并重寫了其configureDefaultServletHandling()方法,通過調(diào)用DefaultServletHandlerConfigurer的enable()方法,我們要求DispatcherServlet將靜態(tài)資源的請求轉(zhuǎn)發(fā)到Servlet容器中默認(rèn)的Servlet上,而不是使用DispatcherServlet本來來處理此類請求。

WebConfig已經(jīng)就緒,那么RootConfig呢?因為本章聚焦于Web開發(fā),而Web相關(guān)的配置通過DisPatcherServlet創(chuàng)建的應(yīng)用上下文都已經(jīng)配好了,因此現(xiàn)在的RootConfig相對很簡單:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
/**
 * Created by guo on 23/2/2018.
 */
@Configuration
@ComponentScan(basePackages = {"com.guo.spittr"},
    excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = EnableWebMvc.class)})
public class RootConfig {

}

唯一需要注意的是RootConfig使用了@ComponentScan注解,這樣的話,我們就有很多機會用非Web的組件來完善RootConfig。

5.1.3 Spittr應(yīng)用簡介

為了實現(xiàn)在線社交的功能,我們將要構(gòu)造一個簡單的微博(microblogging)應(yīng)用,在很多方面,我們所構(gòu)建的應(yīng)用于最早的微博應(yīng)用Twitter很類似,在這個過程中,我們會添加一些小的變化。當(dāng)然我們使用Spirng技術(shù)來構(gòu)建這個應(yīng)用。

因為從Twitter借鑒了靈感并通過Spring來進(jìn)行實現(xiàn),所以它就有了一個名字:Spitter。

Spittr應(yīng)用有兩個基本的領(lǐng)域概念:Spitter(應(yīng)用的用戶)和Spittle(用戶發(fā)布的簡短狀態(tài)更新)。當(dāng)我們在書中完善Spittr應(yīng)用的功能時,將會介紹這兩個概念。在本章中,我們會構(gòu)建應(yīng)用的Web層,創(chuàng)建展現(xiàn)Spittle的控制器以及處理用戶注冊為Spitter的表單。

舞臺已經(jīng)搭建完成了,我們已經(jīng)配置了DispatcherServlet,啟用了基本的Spring MVC組件,并確定了目標(biāo)應(yīng)用。讓我們進(jìn)入本章的核心內(nèi)容:使用Spring MVC 控制器處理Web請求。

5.2 編寫 基本的控制器

在SpringMVC中,控制器只是在方法上添加了@RequestMapping注解的類,這個注解聲明了他們所要處理的請求。

開始的時候,我們盡可能簡單,假設(shè)控制器類要處理對/的請求,并對渲染應(yīng)用的首頁。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

/**
 * Created by guo on 24/2/2018.
 * 首頁控制器
 */
@Controller
public class HomeController {
    @RequestMapping(value = "/",method = RequestMethod.GET)           //處理對“/”的Get請求
    public String home() {
        return "home";                                                //視圖名為home
    }
}

寫完測試了下,好使,

你可能注意到第一件事就是HomeController帶有@Controller注解,很顯然這個注解是用來聲明控制器的,但實際上這個注解對Spirng MVC 本身影響不大。

@Controller是一個構(gòu)造型(stereotype)的注解。它基于@Component注解。在這里,它的目的就是輔助實現(xiàn)組件掃描。因為homeController帶有@Controller注解,因此組件掃描器會自動去找到HomeController,并將其聲明為Spring應(yīng)用上下文中的bean。

Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}

其實你可以讓HomeController帶有@Component注解,它所實現(xiàn)的效果是一樣的。但是在表意性上可能差一些,無法確定HomeController是什么組件類型。

HomeController唯一的一個方法,也就是Home方法,帶有@RequestMapping注解,他的Value屬性指定了這個方法所要處理的請求路徑,method屬性細(xì)化了它所能處理的HTTP方法,在本例中,當(dāng)收到對‘/’的HTTP GET請求時,就會調(diào)用home方法。

home()方法其實并沒有做太多的事情,它返回一個String類型的“home”,這個String將會被Spring MVC 解讀為要渲染的視圖名稱。DispatcherServlet會要求視圖解析器將這個邏輯名稱解析為實際的視圖。

鑒于我們配置InternalResourceViewResolver的方式,視圖名“home”將會被解析為“/WEB-INF/views/home.jsp”

Spittr應(yīng)用的首頁,定義為一個簡單的JSP

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>

  
    Spitter
    " >
  
  
    

Welcome to Spitter

">Spittles | ">Register

測試控制器最直接的辦法可能是構(gòu)建并部署應(yīng)用,然后通過瀏覽器對其進(jìn)行訪問,但是自動化測試可能會給你更快的反饋和更一致的獨立結(jié)果,所以,讓我們編寫一個針對HomeController的測試

5.2.1 測試控制器

編寫一個簡單的類來測試HomoController。

import static org.junit.Assert.*;
import org.junit.Test;

public class HomeControllerTest {
    @Test
    public void testHomePage() throws Exception {
        HomeController controller = new HomeController();
        assertEquals("home",controller.home());
    }
}

在測試中會直接調(diào)用home()方法,并斷言返回包含 "home"值的String類型。它完全沒有站在Spring MVC控制器的視角進(jìn)行測試。這個測試沒有斷言當(dāng)接收到針對“/”的GET請求時會調(diào)用home()方法。因為它返回的值就是“home”,所以沒有真正判斷home是試圖的名稱。

不過從Spring 3.2開始,我們可以按照控制器的方式進(jìn)行測試Spring MVC中的控制器了。而不僅僅是POJO進(jìn)行測試。Spring現(xiàn)在包含了一種mock Spirng MVC 并針對控制器執(zhí)行 HTTP請求的機制。這樣的話,在測試控制器的時候,就沒有必要在啟動Web服務(wù)器和Web瀏覽器了。

為了闡述如何測試Spirng MVC 容器,我們重寫了HomeControllerTest并使用Spring MVC 中新的測試特性。

import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * Created by guo on 24/2/2018.
 */
public class HomeControllerTest1  {
    @Test                                                             //大家在測試的時候注意靜態(tài)導(dǎo)入的方法
    public void testHomePage() throws Exception {
        HomeController controller = new HomeController();
        MockMvc mockMvc =  standaloneSetup(controller).build();       //搭建MockMvc
       mockMvc.perform(get("/"))                                      //對“/”執(zhí)行GET請求,
               .andExpect(view().name("home"));                       //預(yù)期得到home視圖
    }
}

這次我們不是直接調(diào)用home方法并測試它的返回值,而是發(fā)起了對"/"的請求,并斷言結(jié)果視圖的名稱為home,它首先傳遞一個HomeController實例到MockMvcBuilders.strandaloneSetup()并調(diào)用build()來構(gòu)建MockMvc實例,然后它使用MockMvc實例執(zhí)行針對“/”的GET請求,并設(shè)置 期望得到的視圖名稱。

5.2.2 定義類級別的請求處理。

現(xiàn)在,已經(jīng)為HomeController編寫了測試,那么我們可以做一些重構(gòu)。并通過測試來保證不會對功能造成什么破壞。我們可以做的就是拆分@RequestMapping,并將其路徑映射部分放到類級別上

@Controller
@RequestMapping("/")
public class HomeController {
    @RequestMapping(method = RequestMethod.GET)           //處理對“/”的Get請求
    public String home() {
        return "home";                                    //視圖名為home
    }
}

在這個新版本的HomeController中,路徑被轉(zhuǎn)移到類級別的@RequestMapping上,而HTTP方法依然映射在方法級別上。當(dāng)控制器在類級別上添加@RequestMapping注解時,這個注解會應(yīng)用到控制器的所有處理器方法上,處理器方法上的@RequestMapping注解會對類級別上的@RequestMapping的聲明進(jìn)行補充。

就HomeController而言,這里只有一個控制器方法,與類級別的@RequestMapping合并之后,這個方法的@RequestMapping表明home()將會處理對 “/”路徑的GET請求。

有了測試,所以可以確保在這個過程中,沒有對原有的功能造成破壞。

當(dāng)我們修改@RequestMapping時,還可以對HomeController做另一個變更。@RequestMapping的value接受一個String類型的數(shù)組。到目前為止,我們給它設(shè)置的都是一個String類型的‘/’。但是,我們還可以將它映射到對“/Homepage”的請求,只需要將類級別的@RequestMapping改動下

@Controller
@RequestMapping({"/","/Homepage"})
public class HomeController {
  ...
}

現(xiàn)在,HomeController的home()方法可以被映射到對“/”和“/homepage”的GET請求上。

5.2.3 傳遞模型數(shù)據(jù)到視圖中

到目前為止,就編寫超級簡單的控制器來說,HomeController已經(jīng)是一個不錯的樣例了,但是大多數(shù)的控制器并不是那么簡單。在Spring應(yīng)用中,我們需要有一個頁面展示最近提交的Spittle列表。因此,我們需要有一個新的方法來處理這個頁面。

首先需要定義一個數(shù)據(jù)訪問的Repository,為了實現(xiàn)解耦以及避免陷入數(shù)據(jù)庫訪問的細(xì)節(jié)中,我們將Repository定義為一個接口,并在稍后實現(xiàn)它(第十章),此時,我們只需要一個能夠獲取Spittle列表的Repository,

package com.guo.spittr.data;
import com.guo.spittr.Spittle;
import java.util.List;
/**
 * Created by guo on 24/2/2018.
 */
public interface SpittleRepository {
    List finfSpittles(long max, int count);
}

findSpittles()方法接受兩個參數(shù),其中max參數(shù)代表所返回的Spittle中,Spittle ID屬性的最大值,而count參數(shù)表明要返回多少個Spittle對象,為了獲得最新的20個Spittle對象,我們可以這樣調(diào)用方法。

List recent = SpittleRepository.findSpittles(long.MAX_VALUE(),20)

它的屬性包括消息內(nèi)容,時間戳,以及Spittle發(fā)布時對應(yīng)的經(jīng)緯度。

public class Spittle {

  private final Long id;
  private final String message;
  private final Date time;
  private Double latitude;
  private Double longitude;

  public Spittle(String message, Date time) {
    this(null, message, time, null, null);
  }

  public Spittle(Long id, String message, Date time, Double longitude, Double latitude) {
    this.id = id;
    this.message = message;
    this.time = time;
    this.longitude = longitude;
    this.latitude = latitude;
  }

  //Getter和Setter略

  @Override
public boolean equals(Object that) {
  return EqualsBuilder.reflectionEquals(this, that, "id", "time");
}

@Override
public int hashCode() {
  return HashCodeBuilder.reflectionHashCode(this, "id", "time");
}

需要注意的是,我們使用Apache Common Lang包來實現(xiàn)equals()和hashCode()方法,這些方法除了常規(guī)的作用以外,當(dāng)我們?yōu)榭刂破鞯奶幚砥鞣椒ň帉憸y試時,它們也是有用的。

既然我們說到了測試,那么我們繼續(xù)討論這個話題,并為新的控制器方法編寫測試,

@Test
 public void houldShowRecentSpittles() throws Exception {
   List expectedSpittles = createSpittleList(20);
   SpittleRepository mockRepository = mock(SpittleRepository.class);
   when(mockRepository.findSpittles(Long.MAX_VALUE, 20))
       .thenReturn(expectedSpittles);

   SpittleController controller = new SpittleController(mockRepository);
   MockMvc mockMvc = standaloneSetup(controller)
       .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp"))
       .build();

   mockMvc.perform(get("/spittles"))
      .andExpect(view().name("spittles"))
      .andExpect(model().attributeExists("spittleList"))
      .andExpect(model().attribute("spittleList",
                 hasItems(expectedSpittles.toArray())));
 }
/.................佩服老外,測試代碼一大堆,省略了好多,好好研究下,..................../
 private List createSpittleList(int count) {
   List spittles = new ArrayList();
   for (int i=0; i < count; i++) {
     spittles.add(new Spittle("Spittle " + i, new Date()));
   }
   return spittles;
 }
}

測試首先會創(chuàng)建SpittleRepository接口的mock實現(xiàn),這個實現(xiàn)會從他的findSpittles()方法中返回20個Spittle對象,然后將這個Repository注入到一個新的SpittleController實例中,然后創(chuàng)建MockMvc并使用這個控制器。

需要注意的是這個測試在MockMvc構(gòu)造器上調(diào)用了setSingleView().這樣的話,mock框架就不用解析控制器中的視圖名了。在很多場景中,其實沒必要這么做,但是對于這個控制器方法,視圖和請求路徑非常相似,這樣按照默認(rèn)的駛?cè)虢馕鲆?guī)則,MockMvc就會發(fā)生失敗,因為無法區(qū)分視圖路徑和控制器的路徑,在這個測試中,構(gòu)建InternalResourceViewResolver時所設(shè)置的路徑是無關(guān)緊要的,但我們將其設(shè)置為InternalResourceViewResolver一致。

這個測試對“/spittles”發(fā)起Get請求,然后斷言視圖的名稱為spittles并且模型中包含名為spittleList的屬性,在spittleList中包含預(yù)期的內(nèi)容。

當(dāng)然如果此時運行測試的話,它將會失敗。他不是運行失敗,而是編譯的時候就失敗,這是因為我們還沒編寫SpittleController。

@Controller
@RequestMapping("/spittles")
public class SpittleController {
    private SpittleRepository spittleRepository;

    @Autowired
    public  SpittleController(SpittleRepository spittleRepository) {              //注入SpittleRepository
        this.spittleRepository = spittleRepository;
    }
    @RequestMapping(method = RequestMethod.GET)
    public String spittles(Model model) {
        model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE,20));     // 將spittle添加到視圖
        return "spittles";                                                          // 返回視圖名
    }
}

我們可以看到SpittleController有一個構(gòu)造器,這個構(gòu)造器使用@Autowired注解,用來注入SpittleRepository。這個SpittleRepository隨后又在spittls()方法中,用來獲取最新的spittle列表。

需要注意的是我們在spittles()方法中給定了一個Model作為參數(shù)。這樣,spittles()方法就可以將Repository中獲取到的Spittle列表填充到模型中,Model實際上就是一個Map(也就是key-value的集合)它會傳遞給視圖,這樣數(shù)據(jù)就能渲染到客戶端了。當(dāng)調(diào)用addAttribute()方法并且指定key的時候,那么key會根據(jù)值的對象類型來推斷確定。

sittles()方法最后一件事是返回spittles作為視圖的名字,這個視圖會渲染模型。

如果你希望顯示模型的key的話,也可以指定,

@RequestMapping(method = RequestMethod.GET)
public String spittles(Model model) {
    model.addAttribute("spittleList",
        spittleRepository.findSpittles(Long.MAX_VALUE,20));     // 將spittle添加到視圖
    return "spittles";                                          // 返回視圖名
}

如果你希望使用非Spring類型的話,那么可以使用java.util.Map來代替Model

@RequestMapping(method = RequestMethod.GET)
public String spittles(Map model) {
    model.put("spittleList",
        spittleRepository.findSpittles(Long.MAX_VALUE,20));     // 將spittle添加到視圖
    return "spittles";                                          // 返回視圖名
}

既然我們現(xiàn)在提到了各種可替代方案,那下面還有另外一種方式來編寫spittles()方法

@RequestMapping(method = RequestMethod.GET)
public List spittles() {
  return spittleRepository.findSpittles(Long.MAX_VALUE,20));
}

這個并沒有返回值,也沒有顯示的設(shè)定模型,這個方法返回的是Spittle列表。。當(dāng)處理器方法像這樣返回對象或集合時,這個值會放到模型中,模型的key會根據(jù)其類型推斷得出。在本示例中也就是(spittleList)

邏輯視圖的名稱也會根據(jù)請求的路徑推斷得出。因為這個方法處理針對“/spittles”的GET請求,因此視圖的名稱將會是spittles,(去掉開頭的線。)

不管使用哪種方式來編寫spittles()方法,所達(dá)成的結(jié)果都是相同的。模型會存儲一個Spittle列表,ket為spittleList,然后這個列表會發(fā)送到名為spittles的視圖中。視圖的jsp會是“/WEB-INF/views/spittles.jsp”

現(xiàn)在數(shù)據(jù)已經(jīng)放到了模型中,在JSP中該如何訪問它呢?實際上,當(dāng)視圖是JSP的時候,模型數(shù)據(jù)會作為請求屬性放入到請求之中(Request) ,因此在spittles.jsp文件中可以使用JSTL(JavaServer Pages Standard Tag Library) 的標(biāo)簽渲染spittle列表。


  
  • ">
    (, )
  • 盡管SpittleController很簡單,但是它依然比homeController更進(jìn)一步,不過,SpittleController和HomeController都沒有處理任何形式的輸入。現(xiàn)在,讓我們擴(kuò)展SpittleContorller,讓它從客戶端接受一些輸入。

    5.3 接受請求的輸入

    Spring MVC 允許以多種方法將客戶端中的數(shù)據(jù)傳送到控制器的處理器方法中

    查詢數(shù)據(jù)(Query Parameter)

    表單參數(shù)(Form Parameter)

    路徑變量(Path Variable)

    作為開始,先來看下如何處理帶有查詢參數(shù)的請求,這也是客戶端往服務(wù)器發(fā)送數(shù)據(jù)時,最簡單和最直接的方法。

    5.3.1 處理查詢參數(shù)

    在Spittr應(yīng)用中,可能需要處理的一件事就是展現(xiàn)分頁的Spittle列表,如果你想讓用戶每次查看某一頁的Spittle歷史,那么就需要提供一種方式讓用戶傳遞參數(shù)進(jìn)來,進(jìn)而確定展現(xiàn)那些Spittle列表。

    為了實現(xiàn)這個分頁功能,我們編寫的處理方法要接受兩個參數(shù)

    before參數(shù) (表明結(jié)果中所有的SPittle的ID均在這個值之前)

    count參數(shù)(彪悍在結(jié)果中要包含的Spittle數(shù)量)

    為了實現(xiàn)這個功能,我們將程序修改為spittles()方法替換為使用before參數(shù)和count參數(shù)的新spittles()方法。

    首先添加一個測試,這個測試反映了xinspittles()方法的功能

    @Test
    public void shouldShowPagedSpittles() throws Exception {
        List expectedSpittles = createSpittleList(50);
        SpittleRepository mockRepository = mock(SpittleRepository.class);
        when(mockRepository.findSpittles(238900, 50))
                .thenReturn(expectedSpittles);
    
        SpittleController controller = new SpittleController(mockRepository);
        MockMvc mockMvc = standaloneSetup(controller)
                .setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp"))
                .build();
    
        mockMvc.perform(get("/spittles?max=238900&count=50"))
                .andExpect(view().name("spittles"))
                .andExpect(model().attributeExists("spittleList"))
                .andExpect(model().attribute("spittleList",
                        hasItems(expectedSpittles.toArray())));
    }

    這個測試方法關(guān)鍵點在于同時傳入了max和count參數(shù),它測試了這些參數(shù)存在時的處理方法,而另一個則測試了沒有這些參數(shù)的情景。

    在這個測試之后,我們就能確保不管控制器發(fā)生了什么樣的變化,它都能夠處理這兩種類型的請求。

    @RequestMapping(method = RequestMethod.GET)
    public List spittles(
            @RequestParam(value = "max") long max,
            @RequestParam(value = "count") int count) {
        return spittleRepository.findSpittles(max, count);
    }

    SittleController中的處理器方法同時要處理有參數(shù)和沒參數(shù)的場景,那我們需要對其進(jìn)行修改,讓它能接受參數(shù)。同時如果這些參數(shù)在請求中不存在的話,就是用默認(rèn)值Long.MAX_VALUE和20.@RequestParam注解的defaultValue屬性可以完成這個任務(wù)。

    @RequestMapping(method=RequestMethod.GET)
    public List spittles(
        @RequestParam(value="max", defaultValue=MAX_LONG_AS_STRING) long max,
        @RequestParam(value="count", defaultValue="20") int count) {
      return spittleRepository.findSpittles(max, count);
    }

    現(xiàn)在如果max如果沒有參數(shù)指定的話,它將會是Long的最大值。

    因為查詢參數(shù)都是String 類型 ,因此defaultValue屬性需要String類型,

    private static final String MAX_LONG_AS_STRING = long.toString(Long.MAX.VALUE)

    請求中的查詢參數(shù)是往控制器中傳遞信息的常用手段。另外一種方式就是將傳遞的參數(shù)作為請求路徑的一部分。

    5.3.2 通過路徑參數(shù)接受輸入

    假設(shè)我們的應(yīng)用程序需要根據(jù)給定的ID來展現(xiàn)某一個Spittle記錄。其中一種方案就是編寫處理器方法,通過使用@RequestParam注解,讓它接受ID作為查詢參數(shù)。

    @RequestMapping(value="/show",method = RequestMethod.GET)
    public String showSpittle(
          @RequestParam("spittle_id") long spittleId, Model model) {
          model.addAttribute(spittleRepository.findOne(spittleId));
          return "spittle";
    }

    在理想情況下,要識別資源應(yīng)用應(yīng)該通過URL路徑來標(biāo)識,而不是通過查詢參數(shù)。對“/spittles/12345”發(fā)起請求要優(yōu)于對“/spittles/show?spittle_id=12345”發(fā)起的請求。前者能識別出要查詢的資源,而后者描述的是帶有參數(shù)的一個操作——本質(zhì)上是通過HTTP發(fā)起的RPC。

    既然已經(jīng)以面向資源的控制器作為目標(biāo),那我們將這個需求轉(zhuǎn)化為一個測試。

    @Test
    public void testSpittle() throws Exception {
      Spittle expectedSpittle = new Spittle("Hello", new Date());
      SpittleRepository mockRepository = mock(SpittleRepository.class);
      when(mockRepository.findOne(12345)).thenReturn(expectedSpittle);
    
      SpittleController controller = new SpittleController(mockRepository);
      MockMvc mockMvc = standaloneSetup(controller).build();
    
      mockMvc.perform(get("/spittles/12345"))
        .andExpect(view().name("spittle"))                                 //斷言圖片的名稱為spittle
        .andExpect(model().attributeExists("spittle"))                     //預(yù)期Spittle放到了模型之中
        .andExpect(model().attribute("spittle", expectedSpittle));
    }

    這個測試構(gòu)建了一個mockRepository,一個控制器和MockMvc

    到目前為止,我們所編寫的控制器,所有的方法都映射到了靜態(tài)定義好的路徑上,還需要包含變量部分

    為了實現(xiàn)這種路徑變量,Spring MVC允許我們在@RequestMapping路徑中添加占位符,占位符的名稱需要({..}),路徑中的其他部分要與所處理的請求完全匹配,但是占位符可是是任意的值。

    @RequestMapping(value="/{spittleId}",method = RequestMethod.GET)
    public String showSpittle(@PathVariable("spittleId") long spittleId, Model model) {
          model.addAttribute(spittleRepository.findOne(spittleId));
          return "spittle";
    }

    @PathVariable("spittleId") 表明在請求路徑中,不管占位符部分的值是什么都會傳遞給處理器方法的showSpittle參數(shù)中。

    也可以去掉這個value的值,因為方法的參數(shù)碰巧與占位符的名稱相同。

    @RequestMapping(value="/{spittleId}",method = RequestMethod.GET)
    public String showSpittle(@PathVariable long spittleId, Model model) {
          model.addAttribute(spittleRepository.findOne(spittleId));
          return "spittle";
    }

    如果傳遞請求中少量的數(shù)據(jù),那查詢參數(shù)和路徑變量是合適的,但通常我們還需要傳遞很多的數(shù)據(jù),(表單數(shù)據(jù)),那么查詢顯得有些笨拙和受限制了。

    5.4 處理表單

    Web應(yīng)用的功能不局限于為用戶推送內(nèi)容,大多數(shù)的應(yīng)用允許用戶填充表單,并將數(shù)據(jù)提交回應(yīng)用中,通過這種方式實現(xiàn)與用戶的交互。

    使用表單分為兩個方面:展現(xiàn)表單以及處理用戶通過表單提交的數(shù)據(jù)。在Spittr應(yīng)用中,我們需要有個表單讓用戶進(jìn)行注冊,SitterController是一個新的控制器,目前只有一個請求處理的方法來展現(xiàn)注冊表單。

    @Controller
    @RequestMapping("/spitter")
    public class SpitterController {
        //處理對“/spitter/register”
        @RequestMapping(value = "/register",method = RequestMethod.GET)
          public String showRegistrationForm() {
              return "registerForm";
          }
    }

    測試展現(xiàn)表單的控制器方法(老外每次都測試)

    @Test
    public void shouldShowRegistration() throws Exception {
      SpitterController controller = new SpitterController();
      MockMvc mockMvc = standaloneSetup(controller).build();
      mockMvc.perform(get("/spitter/register"))
             .andExpect(view().name("registerForm"));
    }
    }

    這個JSP必須包含一個HTML

    標(biāo)簽,

    
      
      
      

    需要注意的是這里的

    標(biāo)簽中并沒有設(shè)置action屬性。在這種情況下,當(dāng)表單體提交的時,它會提交到與展現(xiàn)時相同的URL路徑上,它會提交到“/spitter/reqister”上。

    這意味著需要在服務(wù)器端編寫該HTTP POST請求。

    5.4.1 編寫處理表單的處理器

    當(dāng)處理注冊表單的POST請求時,控制器需要接受表單數(shù)據(jù),并將表單數(shù)據(jù)保存為Spitter對象。最后為了防止重復(fù)提交(用戶刷新頁面),應(yīng)該將瀏覽器重定向到新創(chuàng)建用戶的基本信息頁面。

    @Test
    public void shouldProcessRegistration() throws Exception {
      SpitterRepository mockRepository = mock(SpitterRepository.class);
      Spitter unsaved = new Spitter("jbauer", "24hours", "Jack", "Bauer", "jbauer@ctu.gov");
      Spitter saved = new Spitter(24L, "jbauer", "24hours", "Jack", "Bauer", "jbauer@ctu.gov");
      when(mockRepository.save(unsaved)).thenReturn(saved);
    
      SpitterController controller = new SpitterController(mockRepository);
      MockMvc mockMvc = standaloneSetup(controller).build();
    
      mockMvc.perform(post("/spitter/register")
             .param("firstName", "Jack")
             .param("lastName", "Bauer")
             .param("username", "jbauer")
             .param("password", "24hours")
             .param("email", "jbauer@ctu.gov"))
             .andExpect(redirectedUrl("/spitter/jbauer"));
    
      verify(mockRepository, atLeastOnce()).save(unsaved);
    }

    希望大家也可以學(xué)會這樣方式

    在構(gòu)建完SpitterRepository的mock實現(xiàn)以及所要執(zhí)行的控制器和MockNvc之后,shouldProcessRegistration()對“/spitter/register”發(fā)起了一個POST請求,作為請求的一部分,用戶信息以參數(shù)的形式放到request中,從而模擬提交的表單。

    /**
     * Created by guo on 24/2/2018.
     */
    @Controller
    @RequestMapping("/spitter")
    public class SpitterController {
    
        private SpitterRepository spitterRepository;
    
        @Autowired
        public SpitterController(SpitterRepository spitterRepository) {      //注入SpiterRepository
            this.spitterRepository = spitterRepository;
        }
    
        @RequestMapping(value = "/register", method = RequestMethod.GET)
        public String showRegistrationForm() {
            return "registerForm";
        }
    
        @RequestMapping(value = "/register",method = RequestMethod.POST)
        public String procesRegistration(Spitter spitter) {
            spitterRepository.save(spitter);                                //保存Spitter
            return "redirect:/spitter/" + spitter.getUsername();            //重定向到基本信息頁面
        }
    }

    返回一個String類型,用來指定視圖。但是這個視圖格式和以前有所不同。這里不僅返回了視圖的名稱供視圖解析器查找目標(biāo)視圖,而且返回的值還帶有重定向的格式return "redirect:/spitter/" 當(dāng)看到視圖格式中有“redirect:”前綴時,它就知道要將其解析為重定向的規(guī)則,而不是試圖的名稱。在本例中,它將會重定向到基本信息的頁面。

    需要注意的是除了可以“redirect”還可以識別“forward:”前綴,請求將會前(forward)往指定的URL路徑,而不再是重定向。

    在SpitterController中添加一個處理器方法,用來處理對基本信息頁面的請求。

    @RequestMapping(value = "/{username}",method = RequestMethod.GET)
    public String showSpitterProfile(@PathVariable String username, Model model) {
        Spitter spitter = spitterRepository.findByUsername(username);
        model.addAttribute(spitter);
        return "profile";
    }

    spitterRepository通過用戶獲取一個Spitter對象,showSpitterProfile()方法得到這個對象并將其添加到模型中,然后返回profile。也就是基本信息頁面的邏輯視圖。

    
      

    Your Profile




    注意:這里使用H2數(shù)據(jù)庫,太有用了。

    @Configuration
    public class DataConfig {
    
      @Bean
      public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.H2)
                .addScript("schema.sql")
                .build();
      }
      @Bean
      public JdbcOperations jdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
      }
    }
    

    如果表單中沒有發(fā)送username或password,會發(fā)生什么情況呢?或者名字太長,由會怎么樣?,接下來,讓我們看一下為表單添加校驗,而從避免數(shù)據(jù)呈現(xiàn)不一致性。

    5.4.2 校驗表單

    如果用戶在提交表單的時候,username和password為空的話,那么將會導(dǎo)致在新建Spitter對象中,username和password是空的String。如果不處理,將會出項安全問題。

    同時我們應(yīng)該阻止用戶提交空的名字。限制這些輸入的長度。

    從Spring 3.0 開始,在Spring MVC中提供了java校驗的API的支持。只需要在類路徑下包含這個JavaAPI的實現(xiàn)即可。比如Hibernate validator.

    Java校驗API定義了多個注解,這些注解可以用在屬性上,從而限制這些屬性的值。

    @Size :所注解的元素必須是String、集合、或數(shù)組,并且長度要符合要求

    @Null :所注解的值必須為Null

    @NotNull :所注解的元素不能為Null。

    @Max :所注解的必須是數(shù)字,并且值要小于等于給定制。

    @Min

    @Past :所注解的元素必須是一個已過期的日期

    @Future :必須是一個將來的日期

    @Pattern:必須匹配給定的正則表達(dá)式

    public class Spitter {
    
      private Long id;
    
      @NotNull
      @Size(min=5, max=16)
      private String username;
    
      @NotNull
      @Size(min=5, max=25)
      private String password;
    
      @NotNull
      @Size(min=2, max=30)
      private String firstName;
    
      @NotNull
      @Size(min=2, max=30)
      private String lastName;
    
      @NotNull
      @Email
      private String email;
    
      忽略其他方法。
    }
    @RequestMapping(value="/register", method=POST)      //老外喜歡靜態(tài)導(dǎo)入特性
    public String processRegistration(
        @Valid Spitter spitter,                          //校驗Spitter輸入
        Errors errors) {
      if (errors.hasErrors()) {
        return "registerForm";                           //如果校驗出現(xiàn)錯誤,則重新返回表單
      }
    
      spitterRepository.save(spitter);
      return "redirect:/spitter/" + spitter.getUsername();
    }

    Spitter參數(shù)添加了@Valid注解,這會告訴Spring,需要確保這個對象滿足校驗限制。

    如果表單出錯的話,那么這些錯誤可以通過Errors進(jìn)行反問。

    很重要一點需要注意的是:Errors參數(shù)要緊跟在帶有Valid注解參數(shù)的后面。@Valid注解所標(biāo)注的就是要校驗的參數(shù)。

    如果沒有錯誤的話,Spitter對象將會通過Repository進(jìn)行保存,控制器會像之前那樣重定向到基本信息頁面。

    5.5 小節(jié)

    在本章中,我們?yōu)榫帉憫?yīng)用程序的Web部分開來一個好頭,可以看到Spring有一個強大而靈活的Web框架。借助于注解,Spring MVC 提供了近似于POJO的開發(fā)模式,這使得開發(fā)處理請求的控制器變得簡單,同時也易于測試。

    當(dāng)編寫控制器的處理方法時,Spring MVC及其靈活。概括來講,如果你的處理器方法需要內(nèi)容的話,只需將對應(yīng)的對象作為參數(shù),而他不需要的內(nèi)容,則沒有必要出現(xiàn)在參數(shù)列表中。這樣,就為請求帶來了無限的可能性,同時還能保持一種簡單的編程模型。

    盡管本章中很多內(nèi)容都是關(guān)于控制器的請求處理的,但是渲染響應(yīng)也同樣重要,我們通過使用JSP的方式,簡單了解了如何為控制器編寫視圖,但是,就Spring MVC視圖來說,它并不是本章所看到的簡單JSP。

    在接下來的第6章,我們將會更深入的學(xué)習(xí)Spring視圖,包括如何在JSP中使用Spring標(biāo)簽庫,還會學(xué)習(xí)如何借助于Apache Tiles為視圖添加一致的結(jié)構(gòu)。同時,還會了解Thymeleaf,這是一個很有意思的JSP替代方法,Spring為其提供了內(nèi)置的支持。

    真的非常期待下一章,,,,,加油

    文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/68555.html

    相關(guān)文章

    • Spring之旅第十站:MVC配置、上傳文件、異常處理、跨重定向請求、為制器添加通知

      摘要:依賴于對請求的支持。使用解析兼容的沒有構(gòu)造器參數(shù),也沒有要設(shè)置的參數(shù),這樣,在應(yīng)用上下文中,將其聲明為就會非常簡單。默認(rèn)是沒有限制的整個請求的容量。 Spring MVC 高級的技術(shù) 本章內(nèi)容: Spring MVC配置的替代方案 處理文件上傳 在控制器中處理異常 使用flash屬性 稍等還沒結(jié)束 說明 如果你有幸能看到。后面的章節(jié)暫時不更新了,改變學(xué)習(xí)方式了。重要理解思想,這本書...

      leanote 評論0 收藏0
    • Spring實戰(zhàn)5-基于Spring構(gòu)建Web應(yīng)用

      摘要:的框架用于解決上述提到的問題,基于模型,可以幫助開發(fā)人員構(gòu)建靈活易擴(kuò)展的應(yīng)用。在這一章中,將專注于構(gòu)建該應(yīng)用的層,創(chuàng)建控制器和顯示,以及處理用戶注冊的表單。類有兩個靜態(tài)接口,代表兩種模擬服務(wù)的方式獨立測試和集成測試。 主要內(nèi)容 將web請求映射到Spring控制器 綁定form參數(shù) 驗證表單提交的參數(shù) 寫在前面:關(guān)于Java Web,首先推薦一篇文章——寫給java web一年左右...

      sourcenode 評論0 收藏0
    • Spring MVC概念

      摘要:在中,就是前端控制器的任務(wù)是將請求發(fā)送給控制器。處理器映射會根據(jù)請求所攜帶的信息來進(jìn)行決策一旦選擇了合適的控制器,會將請求發(fā)送給選中的控制器。這些信息被稱為模型。因此無需在配置類中顯式聲明任何的控制器具體來講是試圖解析器。 Spring MVC基于模型-視圖-控制器(Model-View-Controller,MVC)模式實現(xiàn),能夠構(gòu)建像Spring框架那樣靈活和松耦合的Web應(yīng)用程序...

      lindroid 評論0 收藏0
    • 如何向一個WebApp引入SpringSpring MVC

      摘要:可以發(fā)現(xiàn),這兩個類都是可以被實例化的,且構(gòu)造器不需要參數(shù)。這段代碼的后半部分其實沒有什么新意,但下半部分的第一行非常關(guān)鍵接受一個作為構(gòu)造器參數(shù)這實際上解決了我們在第四章測試失敗后反思的可能的疑惑我們配置的容器實際上并沒有和融合起來。 如何向一個WebApp引入Spring與Spring MVC 1 在Servlet 3.0環(huán)境中,容器(加載運行webapp的軟件,如Tomcat)會在類...

      maochunguang 評論0 收藏0
    • 通過項目逐步深入了解Spring MVC(一)

      摘要:是一個基于的框架??刂破鲗⒁晥D響應(yīng)給用戶通過視圖展示給用戶要的數(shù)據(jù)或處理結(jié)果。有了減少了其它組件之間的耦合度。 相關(guān)閱讀: 本文檔和項目代碼地址:https://github.com/zhisheng17/springmvc 轉(zhuǎn)載請注明出處和保留以上文字! 了解 Spring: Spring 官網(wǎng):http://spring.io/ 一個好的東西一般都會有一個好的文檔解釋說明,如果你...

      whataa 評論0 收藏0

    發(fā)表評論

    0條評論

    最新活動
    閱讀需要支付1元查看
    <