Spring实战(五:构建Spring Web应用程序)

    SpringMVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够构建像Spring框架那样灵活和松耦合的Web应用程序。

1.Spring MVC基础

1.跟踪Spring MVC的请求

    请求旅程的第一步是Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器(front controller)Servlet。前端控制器是常用的Web应用程序模式,在这里一个单实例的Servlet将请求委托给应用程序的其他组件来执行实际的处理。在Spring MVC中,DispatcherServlet就是前端控制器。

    DispatcherServlet的任务是将请求发送给Spring MVC控制器(controller)。控制器是一个用于处理请求的Spring组件。在典型的应用程序中可能会有多个控制器,DispatcherServlet需要知道应该将请求发送给哪个控制器。所以DispatcherServlet以会查询一个或多个处理器映射(handler mapping)来确定请求的下一站在哪里。处理器映射会根据请求所携带的URL信息来进行决策。

    选择了合适的控制器后,DispatcherServlet会将请求发送给选中的控制器。到了控制器,请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。(实际上,设计良好的控制器本身只处理很少甚至不处理工作,而是将业务逻辑委托给一个或多个服务对象进行处理。)

    控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示。这些信息被称为模型(model)。不过仅仅给用户返回原始的信息是不够的——这些信息需要以用户友好的方式进行格式化,一般会是HTML。所以,信息需要发送给一个视图(view),通常会是JSP。

    控制器所做的最后一件事就是将模型数据打包,并且标示出用于渲染输出的视图名。它接下来会将请求连同模型和视图名发送回DispatcherServlet。

2.搭建Spring MVC

    1.配置DispatcherServlet

    DispatcherServlet是Spring MVC的核心。在这里请求会第一次接触到框架,它要负责将请求路由到其他的组件之中.

    2.启用Spring MVC

    以前,Spring是使用XML进行配置的,你可以使用<mvc:annotation-driven>启用注解驱动的Spring MVC。下面贴上通过JavaConfig方式配置的Spring MVC

    WebConfig添加了@Component-Scan注解,因此将会扫描spitter.web包来查找组件。@Controller注解,会使其成为组件扫描时的候选bean。因此,我们不需要在配置类中显式声明任何的控制器。

    接下来添加了一个ViewResolverbean。更具体来讲,是Internal-ResourceViewResolver。这就是视图解析器。我们只需要知道它会查找JSP文件,在查找的时候,它会在视图名称上加一个特定的前缀和后缀(例如,名为home的视图将会解析为/WEB-INF/views/home.jsp)。我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求。

    RootConfig:

3.Spittr应用简介

    Spittr应用有两个基本的领域概念:Spitter(应用的用户)和Spittle(用户发布的简短状态更新)。

2.编写基本的控制器

    在Spring MVC中,控制器只是方法上添加了@RequestMapping注解的类,这个注解声明了它们所要处理的请求。

    HomeController是一个构造型(stereotype)的注解,它基于@Component注解。在这里,它的目的就是辅助实现组件扫描。因为HomeController带有@Controller注解,因此组件扫描器会自动找到HomeController,并将其声明为Spring应用上下文中的一个bean。也可以让HomeController带有@Component注解,它所实现的效果是一样的,但是在表意性上可能会差一些,无法确定HomeController是什么组件类型。

    home()方法,带有@RequestMapping注解。它的value属性指定了这个方法所要处理的请求路径,method属性细化了它所处理的HTTP方法。在本例中,当收到“/”的HTTP GET请求时,就会调用home()方法。

    它返回了一个String类型的“home”。这个String将会被Spring MVC解读为要渲染的视图名称。DispatcherServlet会要求视图解析器将这个逻辑名称解析为实际的视图。鉴于我们配置InternalResourceViewResolver的方式,视图名“home”将会解析为“/WEB-INF/views/home.jsp”路径的JSP。

(详细的spring与spirngmvc的配置可以查看我的ssm整合

1.测试控制器

    它首先传递一个HomeController实例到MockMvcBuilders.standaloneSetup()并调用build()来构建MockMvc实例。然后它使用MockMvc实例来执行针对“/”的GET请求并设置期望得到的视图名称。

2.定义类级别的请求

    当控制器在类级别上添加@RequestMapping注解时,这个注解会应用到控制器的所有处理器方法上。处理器方法上的@RequestMapping注解会对类级别上的@RequestMapping的声明进行补充。

    对HomeController而言,这里只有一个控制器方法。与类级别的@Request-Mapping合并之后,这个方法的@RequestMapping表明home()将会处理对“/”路径的GET请求。

    @RequestMapping的value属性能够接受一个String类型的数组。到目前为止,我们给它设置的都是一个String类型的“/”。但是,我们还可以将它映射到对“/homepage”的请求,只需将类级别的@RequestMapping改为如下所示:

现在,HomeController的home()方法能够映射到对“/”和“/homepage”的GET请求。

3.传递模型数据到视图中

    Model实际上就是一个Map(也就是key-value对的集合),它会传递给视图,这样数据就能渲染到客户端了。当调用addAttribute()方法并且不指定key的时候,那么key会根据值的对象类型推断确定。这里设置了key为list。假如不设置key,然后值是List<Spittle>,则键将会推断为spittleList。

假如有这么一个控制器:


替代方案:

另一种:

    这个版本与其他的版本有些差别。它并没有返回视图名称,也没有显式地设定模型,这个方法返回的是Spittle列表。当处理器方法像这样返回对象或集合时,这个值会放到模型中,模型的key会根据其类型推断得出(在本例中,也就是spittleList)。
    而逻辑视图的名称将会根据请求路径推断得出。因为这个方法处理针对“/spittles”的GET请求,因此视图的名称将会是spittles(去掉开头的斜线)。

页面上输出为:

3.接受请求的输入

Spring MVC允许以多种方式将客户端中的数据传送到控制器的处理器方法中,包括:
查询参数(Query Parameter)。
表单参数(Form Parameter)。
路径变量(Path Variable)。

1.处理查询参数

    如果max参数没有指定的话,它将会是Long类型的最大值。因为查询参数都是String类型的,因此defaultValue属性需要String类型的值。因此,使用Long.MAX_VALUE是不行的。我们可以将Long.MAX_VALUE转换为名为MAX_LONG_-AS_STRING的String类型常量:

    defaultValue属性给定的是String类型的值,但是当绑定到方法的max参数时,它会转换为Long类型。如果请求中没有count参数的话,count参数的默认值将会设置为20。

    请求中的查询参数是往控制器中传递信息的常用手段。另外一种方式就是将传递参数作为请求路径的一部分,这种方式在构建面向资源的控制器时很有用。

2.通过路径参数接受输入

    通过使用@RequestParam注解,让它接受ID作为查询参数:

这个处理器方法将会处理形如“/spittles/show?spittle_id=12345”这样的请求。

    为了实现路径变量,Spring MVC允许我们在@RequestMapping路径中添加占位符。占位符的名称要用大括号(“{”和“}”)括起来。路径中的其他部分要与所处理的请求完全匹配,但是占位符部分可以是任意的值。

    我们可以看到,spittle()方法的spittleId参数上添加了@PathVariable("spittleId")注解,这表明在请求路径中,不管占位符部分的值是什么都会传递到处理器方法的spittleId参数中。如果对“/spittles/54321”发送GET请求,那么将会把“54321”传递进来,作为spittleId的值。

4.处理表单

因为没有设置action属性所以它会提交到当前路由

    InternalResourceViewResolver看到视图格式中的“redirect:”前缀时,它就知道要将其解析为重定向的规则,而不是视图的名称。在本例中,它将会重定向到用户基本信息的页面。例如,如果Spitter.username属性的值为“jbauer”,那么视图将会重定向到“/spitter/jbauer”。需要注意的是,除了“redirect:”,InternalResourceViewResolver还能识别“forward:”前缀。当它发现视图格式中以“forward:”作为前缀时,请求将会前往(forward)指定的URL路径,而不再是重定向。

校验表单

使用方式:

    Spitter的所有属性都添加了@NotNull注解,以确保它们的值不为null。类似地,属性上也添加了@Size注解以限制它们的长度在最大值和最小值之间。对Spittr应用来说,这意味着用户必须要填完注册表单,并且值的长度要在给定的范围内。

    Spitter参数添加了@Valid注解,这会告知Spring,需要确保这个对象满足校验限制。在Spitter属性上添加校验限制并不能阻止表单提交。即便用户没有填写某个域或者某个域所给定的值超出了最大长度,processRegistration()方法依然会被调用。这样,我们就需要处理校验的错误,就像在processRegistration()方法中所看到的那样。如果有校验出现错误的话,那么这些错误可以通过Errors对象进行访问,现在这个对象已作为processRegistration()方法的参数。(很重要一点需要注意,Errors参数要紧跟在带有@Valid注解的参数后面,@Valid注解所标注的就是要检验的参数。)processRegistration()方法所做的第一件事就是调用Errors.hasErrors()来检查是否有错误。如果有错误的话,Errors.hasErrors()将会返回到registerForm,也就是注册表单的视图。这能够让用户的浏览器重新回到注册表单页面,所以他们能够修正错误,然后重新尝试提交。


猜你喜欢

转载自blog.csdn.net/qq_37598011/article/details/80739281