构建Spring Web应用程序

学习内容

映射请求到Spring控制器

透明地绑定表单参数

校验表单提交

简介

状态管理、工作流以及验证都是需要解决的重要特性,HTTP协议的无状态性决定了这些问题都不那么容易解决。

Spring的Web框架就是为了解决这些关注点而设计的。Spring MVC基于模型-视图-控制器模式(Model-View-Controller,MVC)实现,他能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序。

Spring MVC起步

Spring将请求在调度Servlet、处理器映射(handler mapping)、控制器以及视图解析器(view resolver)之间移动。

1、跟踪Spring MVC的请求

 

流程详解:

在请求离开浏览器时<1>,会带有用户所请求内容的信息,至少会包含请求的URL。但是还可能带有其他的信息。例如用户提交的表单信息。

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

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

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

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

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

这样,控制器就不会与特定的视图相耦合,传递给DispatcherServlet的视图名并不会直接标示某个特定的JSP。实际上,他甚至并不能确定视图就是JSP。相反,他仅仅传递了一个逻辑名称,这个名字将会用来查找产生结果的真正视图。DispatcherServlet将会使用视图解析器(view resolver)<5>来将逻辑视图名匹配为一个特定的视图实现,他可能是也可能不是JSP。

既然DispatcherServlet已经知道由那个视图渲染结果,那请求的任务基本上也就完成了。他的最后一站是视图的实现(可能是JSP)<6>,在这里他交付模型数据。请求的任务就完成了。视图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端(不会像听上去那样硬编码)。

2、搭建Spring MVC

配置DispatcherServlet

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

Servlet3规范之前和Spring3.1之前:DispatcherServlet这样的Servlet会配置在web.xml文件中,这个文件会放到应用的WAR包里面。

Servlet3规范之后和Spring3.1之后:可以使用Java将DispatcherServlet配置在Servlet容器中,而不会再使用web.xml文件。

配置DispatcherServlet代码如下:

package spittr.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import spittr.web.WebConfig;

public class SpitterWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override

protected Class<?>[] getRootConfigClasses() {

return new Class<?>[] { RootConfig.class };

}

@Override

protected Class<?>[] getServletConfigClasses() {

return new Class<?>[] { WebConfig.class };

}

@Override

protected String[] getServletMappings() {

return new String[] { "/" };

}

}

配置DispatcherServlet代码分析:

AbstractAnnotationConfigDispatcherServletInitializer剖析

扩展AbstractAnnotationConfigDispatcherServletInitializer的任意类都会自动地配置DispatcherServlet和Spring应用上下文,Spring的应用上下文会位于应用程序的Servlet上下文之中。在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果能发现的话,就会用他来配置Servlet容器。Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给他们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,也就是AbstractAnnotationConfigDispatcherServletInitializer。SpitterWebInitializer扩展了AbstractAnnotationConfigDispatcherServletInitializer,因此当部署到Servlet3.0容器中的时候,容器会自动发现他,并用它来配置Servlet上下文。

第一个方法getServletMappings()

他会将一个或多个路径映射到DispatcherServlet上,本例中映射的是“/”,他表示会是应用的默认Servlet。他会处理进入应用的所有请求。

两个应用上下文之间的关系

当DispatcherServlet启动的时候,他会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean。getServletConfigClasses()方法中,我们要求DispatcherServlet加载应用上下文时,使用定义在WebConfig配置类中的bean。

但是在Spring Web应用中,通常还会有另外一个应用上下文。另外的这个应用上下文是由ContextLoaderListener创建的。我们希望DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean。这些bean通常是驱动应用后端的中间层和数据层组件。

实际上,AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServlet和ContextLoaderListener。getServletConfigClasses()方法返回的带有@Configuration注解的类将会用来定义DispatcherServlet应用上下文中的Bean。getRootConfigClasses()方法返回的带有@Configuration注解的类将会用来配置ContextLoaderListener创建的应用上下文中的bean。

AbstractAnnotationConfigDispatcherServletInitializer来配置DispatcherServlet是传统web.xml方式的替代方案。只能部署到支持Servlet3.0的服务器中。

3、启用Spring MVC

XML配置:可以使用<mvc:annotation-driven>启动注解驱动的Spring MVC。

Java配置:@EnableWebMvc注解类

package org.hhc.spittr.config;

import org.springframework.context.annotation.Configuration;

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

@Configuration

@EnableWebMvc

public class Webconfig {

}

这可以运行起来,他的确能够启动Spring MVC,但还有不少问题要解决:

没有配置视图解析器。Spring默认会使用BeanNameView-Resolver,这个视图解析器会查找ID与视图名称匹配的Bean,并且查找的bean要实现View接口,他以这样的方式来解析视图。

没有启动组件扫描。

WebConfig最小但可用Spring MVC配置

package org.hhc.spittr.config;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.servlet.ViewResolver;

import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;

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

import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration

@EnableWebMvc

@ComponentScan("org.hhc.spittr.web")

public class Webconfig extends WebMvcConfigurerAdapter {

@Bean

public ViewResolver viewResolver() {

InternalResourceViewResolver resolver = new InternalResourceViewResolver();

resolver.setPrefix("/WEB-INF/views/");

resolver.setSuffix(".jsp");

return resolver;

}

@Override

public void configureDefaultServletHandling(

DefaultServletHandlerConfigurer configurer) {

configurer.enable();

}

}

通过调用DefaultServletHandlerConfigurer的enable()方法,我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身来处理此请求。

RootConfig配置比较简单,使用@ComponentScan注解,我们就有很多机会用非Web的组件来充实完善RootConfig。

编写基本的控制器

1、编写控制器

package org.hhc.spittr.web;

import static org.springframework.web.bind.annotation.RequestMethod.*;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

@Controller

@RequestMapping("/")

public class HomeController {

@RequestMapping(method =GET)

public String home(Modelmodel) {

return "home";

}

}

@RequestMapping注解:value代表路径;method属性细化了可处理的HTTP方法。

@Controller注解:他基于@Component注解。

2、测试控制器

package org.hhc.spittr.web;

import org.junit.Test;

import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;

public class HomeControllerTest {

@Test

public void testHomePage()throws Exception {

HomeController controller =new HomeController();

MockMvc mockMvc =standaloneSetup(controller).build();

mockMvc.perform(get("/")).andExpect(

view().name("home"));

}

}

3、定义类级别的请求处理

使用的还是@RequestMapping

4、传递模型数据到视图中

@Controller

@RequestMapping("/spittles")

public class SpittleController {

private SpittleRepositoryrepository;

@Autowired

public SpittleController(SpittleRepositoryrepository) {

this.repository =repository;

}

/**

* @param model:map的key根据对象类型推断确定:spittleList

* @return

*/

@RequestMapping(method=RequestMethod.GET)

public Stringspittles(Model model) {

model.addAttribute(repository.findSpittles(Long.MAX_VALUE, 20));

return "spittles";

}

/**

* @param model:指定key

* @return

*/

@RequestMapping(method = RequestMethod.GET)

public Stringspittles(Model model) {

model.addAttribute("spittleList",

repository.findSpittles(Long.MAX_VALUE, 20));

return "spittles";

}

/**

* @param model:如果希望使用非Spring类型的话,可以用Map来代替Model

* @return

*/

@RequestMapping(method = RequestMethod.GET)

public String spittles(Map model) {

model.put("spittleList",

repository.findSpittles(Long.MAX_VALUE, 20));

return "spittles";

}

/**

* 处理器方法像这样返回对象或集合时,这个值会放到模型中,模型的key会根据类型推断得出

* 逻辑视图的名称将会根据请求路径推断得出。本例中视图名为:spittles

* @return

*/

@RequestMapping(method = RequestMethod.GET)

public List<Spittle> spittles() {

return repository.findSpittles(Long.MAX_VALUE, 20);

}

}

上面选择哪种方式来编写spittles()方法,所达到的结果都是相同的。模型中会存储一个spittle列表,key为spittleList,然后这个列表会发送到名为spittles的视图中。按照我们配置的视图解析器,视图的JSP将会是”WEB-INF/views/spittles.jsp”。

接受请求的输入

Spring MVC允许以多种方式将客户端中的数据传送到控制器的处理器方法中,包括:

查询参数

表单参数

路径变量

1、处理查询参数

@RequestMapping(method = RequestMethod.GET)

public List<Spittle> spittles(@RequestParam(value="max", defaultValue="20")long max,

@RequestParam(value="count", defaultValue="20")int count) {

return repository.findSpittles(max,count);

}

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

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)

public String showSpittle(@PathVariable("spittleId")long spittleId, Model model){

return "spittle";

}

当占位符的名称与方法的参数名相同时,才可以简写:

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)

public String showSpittle(@PathVariable long spittleId, Model model) {

return "spittle";

}

处理表单

Web应用允许用户填充表单并将数据提交回应用中,通过这种方式实现与用户的交互。

使用表单分为两个方面:展现表单和处理用户通过表单提交的数据。

1、校验表单

@RequestMapping(value="/register", method=POST)

public String processRegistration(

@Valid Spitterspitter,

Errors errors) {

if (errors.hasErrors()) {

return "registerForm";

}

spitterRepository.save(spitter);

return "redirect:/spitter/" +spitter.getUsername();

}

public class Spitter {

private Longid;

@NotNull

@Size(min=5, max=16)

private Stringusername;

@NotNull

@Size(min=5, max=25)

private Stringpassword;

@NotNull

@Size(min=2, max=30)

private StringfirstName;

@NotNull

@Size(min=2, max=30)

private StringlastName;

@NotNull

@Email

private Stringemail;

}

第5章-构建Spring Web应用程序相关推荐

  1. Spring实战 | 第二部分 Web中的Spring(第五章 构建Spring Web应用程序)

    第五章 构建Spring Web应用程序 映射请求到Spring控制器 透明地绑定表单参数 校验表单提交 一.Spring MVC起步 1.跟踪spring MVC的请求 在请求离开浏览器时,会带有用 ...

  2. spring(5)构建 spring web 应用程序

    [0]README 1)本文部分文字描述转自:"Spring In Action(中/英文版)",旨在review  "spring(5)构建 spring web 应用 ...

  3. 使用Hibernate和Spring构建Java Web应用程序

    这篇文章将展示如何在Spring环境中使用带有Hibernate ORM的MYSQL DB创建学生注册应用程序. 这是一个简单的应用程序,旨在在注册过程中从用户收集输入详细信息,将这些详细信息保存在M ...

  4. 使用MyBatis和Spring构建Java Web应用程序

    这篇文章将展示如何在Spring环境中使用带有MyBatis框架的MYSQL DB创建学生注册应用程序. 这是一个简单的应用程序,旨在在注册期间从用户收集输入详细信息,将详细信息保存在MYSQL DB ...

  5. 使用Spring的Hibernate构建Java Web应用程序

    这篇文章将展示如何在Spring环境中使用带有Hibernate ORM的MYSQL DB创建学生注册应用程序. 这是一个简单的应用程序,旨在在注册期间从用户收集输入详细信息,将详细信息保存在MYSQ ...

  6. 程序员疯狂记事:如何利用众多技术栈构建一个 Web 应用程序?!

    [CSDN 编者按]"Elixir.Phoenix.Absinthe.GraphQL.React和Apollo"--在这几个关键词中,有几个是身为开发者的你一直想玩但还没来得及玩的 ...

  7. spring_了解Spring Web应用程序体系结构:经典方法

    spring 每个开发人员必须了解两件事: 架构设计是必要的. 精美的架构图并未描述应用程序的真实架构. 真正的体系结构是从开发人员编写的代码中找到的,如果不设计应用程序的体系结构,最终将得到一个具有 ...

  8. spring体系结构_了解Spring Web应用程序体系结构:经典方法

    spring体系结构 每个开发人员必须了解两件事: 架构设计是必要的. 花哨的体系结构图没有描述应用程序的真实体系结构. 真正的体系结构是从开发人员编写的代码中找到的,如果不设计应用程序的体系结构,最 ...

  9. java web mvc_构建Java Web应用程序时遵循MVC的三个步骤

    java web mvc 第1步 做 始终通过servlet / action bean处理URL(POST表单,单击链接等),而不是通过JSP处理 为什么 ActionBeans(无论某些框架调用那 ...

  10. 了解Spring Web应用程序体系结构:经典方法

    每个开发人员必须了解两件事: 架构设计是必要的. 花哨的体系结构图没有描述应用程序的真实体系结构. 真正的体系结构是从开发人员编写的代码中找到的,如果不设计应用程序的体系结构,最终将得到一个具有多个体 ...

最新文章

  1. 学python要下载什么-从应用的角度去学习Python--为孩子下载课本
  2. CODE 大全网站整站源码分享(带数据库)
  3. SQLServer------聚集索引和非聚集索引的区别
  4. LiveVideoStack线上分享第三季(四):计算存储在视频转码中的应用
  5. 分布式拒绝服务攻击(DDoS)原理及防范
  6. 深入深出Sigmoid与Softmax的血缘关系
  7. C#组成考题字符串【C#】
  8. VirtualBox linux 网络设置 Bridged Adapter模式
  9. vega56刷64_Vega56刷入BIOS跑分直逼旗舰Vega64
  10. Swift教程_零基础学习Swift完整实例(八)_swift完整实例(添加View的动画效果、添加View的阴影)...
  11. linux Redis下载及安装
  12. 阿里云在安全方面有哪些防护措施
  13. 互联网快讯:粉笔科技双轨并进未来可期;猿辅导优质教学获赞赏;网红奶茶古茗被罚
  14. 图片放大-jQuery脚本使用异常:仅闪现图片外框
  15. 移动研发平台EMAS 3.0全新升级,欢迎登陆阿里云官网搜索EMAS进行体验
  16. 在MySQL中第一章选择题_北大青鸟第二学期 123章数据库选择题
  17. android 微信好友,朋友圈分享
  18. 飞桨框架v2.3 API最新升级 | 对科学计算、概率分布和稀疏Tensor等提供更全面支持
  19. BugkuCTF-Web-你必须让他停下
  20. 0120 C指针跳转、数组名指向(笔记)

热门文章

  1. 基于云计算的毕业设计题目
  2. SUSE Linux 15 If ‘netstat‘ is not a typo you can use command-not-found to lookup the package...
  3. Fail to open the referenced table
  4. 【7gyy】cdma无线通讯上使用的技术
  5. java分类Kdd99数据集_【数据】主题分类数据集
  6. RocketMQ独孤九剑-总纲
  7. 通道和色彩调整——冷色调图片
  8. php implode(),php implode函数怎么用
  9. onclick和onfocus的区别
  10. 车厢调度(信息学奥赛一本通 - T1357)