Spring MVC-03循序渐进之Spring MVC(spring boot)

网友投稿 677 2022-05-30

概述

前面两篇介绍了模型2架构的优势以及如何构建一个模型2应用。但是Spring MVC框架可以帮助我们快速的开发MVC应用。

Spring MVC体系概述

若基于某个框架来开发一个模型2的应用程序,我们要负责编写一个Dispatcher servlet和控制类。 其中Dispatcher servlet必须能够做到如下事情:

根据URI调用对应的action

实例化正确的控制器类

根据请求参数来构造表单bean

调用控制器对象的相应方法

转向一个视图

Spring MVC框架围绕DispatcherServlet这个核心展开,DispatcherServlet负责截获请求并分派给相应的处理器处理。 SpringMVC框架包括注解驱动控制器、请求及响应的信息处理、视图解析、本地化解析、上传文件解析、异常处理及表单标签绑定等内容。

由于SpringMVC是基于Model2实现的框架,所以它底层的机制也是MVC,我们来看下SpringMVC的整体架构

从接收请求到返回相应,Spring MVC框架的众多组件有条不紊的完成内部的分工,在整个框架中,DispatcherServlet处于核心的位置,负责协调和组织不同组件以完成请求处理并返回响应的工作。

下面我们来分步解析下SpringMVC处理请求的整体过程

整个过程始于客户端发出的一个HTTP请求,Web应用服务器收到这个请求后,如果匹配DispatcherServlet的请求映射路径(web.xml中指定),则web容器将该请求交给DispatcherServlet处理

DispatcherServlet接收到这请求后,将根据请求的信息(包括url,HTTP方法、请求报文头、请求参数、Cookie等)及HandlerMapping的配置找到处理请求的处理器(Handler)。 可将HandlerMapping看做是路由控制器,将Handler看做目标主机。值得注意的是,SpringMVC中并没有定义一个Handler接口,实际上任何一个Object都可以称为请求处理器。

当DispatcherServlet根据HandlerMapping得到对应请求的Handler后,通过HandlerAdpapter对Handler进行封装再以统一的适配器接口调用Handler.

处理器完成业务逻辑的处理后将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息

ModelAndView并非真正的视图对象,DispatcherServlet通过ViewResolver完成逻辑视图和真实视图对象的解析工作

当得到真实的视图对象View后,DispatcherServlet就使用这个View对ModelAndView中的模型数据进行视图渲染

最终客户端得到相应消息可能是一个普通的html页面,也可能是要给XML或者JSON串,甚至是一张图片或者PDF文档等不同的媒体形式。

Spring MVC的DispatcherServlet

我们在前面两篇博文的例子中,servlet需要我们自己编写,基于Spring MVC ,则无需如此。

SpringMVC中自带了一个开箱即用的DispatcherServlet,全限定名为org.springframework.web.servlet.DispatcherServlet

使用DispatcherServlet

要想使用这个servlet,同样的也需要把它配置在部署描述符(web.xml)、应用servlet和servlet-mapping。如下所示

springmvc org.springframework.web.servlet.DispatcherServlet 1 springmvc /

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

servlet元素内的on-startup是可选项,

如果它存在,则它将在应用程序启动时装载servlet并调用他的init方法,若不存在,则该servlet的第一个请求时加载

DispatcherServlet将使用Spring MVC诸多默认的组件,此外,

初始化的时候,它会寻找一个在应用程序的WEB-INF目录下的配置文件,该配置文件的命名规则 servletName-servlet.xml

。 其中servletName是在部署描述中的DispatcherServlet的名称,比如我们上述的配置文件 springmvc,则在WEB-INF下对应的文件为springmvc-servlet.xml.

此外,也可以把SpringMVC的配置文件放在应用程序目录中的任何地方,用servlet定义的init-param元素,以便DispatcherServlet加载到该文件。 init-param元素拥有一个contextConfigLocation的param-name元素,其param-value元素则包含配置文件的路径。

如下所示

springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/config/simple-config.xml 1

1

2

3

4

5

6

7

8

9

10

11

Controller接口

Spring2.5之前

,开发一个控制器的唯一方法是实现org.springframework.web.servlet.mvc.Controller接口,该接口中有一个方法

ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;

1

其实现类可以访问对应请求的HttpServletRequest 和HttpServletResponse ,同时还必须返回包含视图路径或者视图路径和模的ModelAndView 对象。

Controller接口实现类只能处理一个单一动作,而一个基于注解的控制器可以同时支持多个请求处理动作,并且无需实现任何接口(后续介绍这种主流的开发方式,这里先演示下实现接口的方式)

简单示例(实现接口的方式)

在这里我们只是简单的演示一下这种方式的用法,实际开发中并不推荐这样做。基于注解的方式后续介绍。

maven工程结构如下:

pom.xml添加依赖

4.0.0 com.artisan chapter03a war 0.0.1-SNAPSHOT chapter03a Maven Webapp http://maven.apache.org junit junit 3.8.1 test javax.servlet javax.servlet-api 3.1.0 provided org.springframework spring-webmvc 4.3.9.RELEASE log4j log4j 1.2.17 chapter03a org.apache.maven.plugins maven-compiler-plugin 2.5.1 1.7 1.7 -Xlint:all true true

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

部署描述文件和Spring MVC 的配置文件

部署描述文件web.xml

springmvc org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/config/artisan-servlet.xml 1 springmvc *.action

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

这里告诉Servlet/JSP容器,我们将使用SpringMVC的DispatcherServlet,并通过配置url-pattern原始来匹配.action结尾的URL映射到该servlet。 并通过init-param元素,加载特定目录下的Spring MVC 配置文件人,如果不配置的话,则SpringMVC的配置文件将在默认的/WEB-INF目录下,并且按照约定的命名规范。

Spring MVC配置文件

1

2

3

4

5

6

7

8

9

10

这里声明两个控制器类InputProductController和SaveProductController,并分别映射到/product_input.action和/product_save.action。

Controller

下面来编写“传统”风格的控制器,分别实现Spring提供的Controller接口

package com.artisan.springmvc.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; /** * * @author Mr.Yang * @Desc 实现Spring自身的Controller * */ public class InputProductController implements Controller{ private static final Logger logger = Logger.getLogger(InputProductController.class); @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.info("InputProductController called"); return new ModelAndView("/WEB-INF/jsp/ProductForm.jsp"); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

InputProductController 类的handleRequest方法只返回一个ModelAndView对象,包含一个视图,并没有模型。因此,该请求将被转发到/WEB-INF/jsp/ProductForm.jsp页面

package com.artisan.springmvc.controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import com.artisan.springmvc.form.ProductForm; import com.artisan.springmvc.model.Product; /** * * @author Mr.Yang * @Desc 实现Spring自身的Controller * */ public class SaveProductController implements Controller{ private static final Logger logger = Logger.getLogger(SaveProductController.class); @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { logger.info("SaveProductController called"); ProductForm productForm = new ProductForm(); // populate action properties productForm.setName(request.getParameter("name")); productForm.setDescription(request.getParameter("description")); productForm.setPrice(request.getParameter("price")); // create model Product product = new Product(); product.setName(productForm.getName()); product.setDescription(productForm.getDescription()); try { product.setPrice(Float.parseFloat(productForm.getPrice())); } catch (NumberFormatException e) { } // insert code to save Product return new ModelAndView("/WEB-INF/jsp/ProductDetails.jsp", "product", product); } }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

SaveProductController类的handleRequest方法中,首先用请求创建了一个ProductForm对象,然后它根据ProductForm对象创建Product对象 。 由于ProductForm的price是一个字符串,而在Product类中是一个float类型,因此需要转型(

后面会介绍通过数据绑定省去ProductForm,这里暂不讲解)

SaveProductController的handleRequest方法返回最后的ModelAndView模型包含了视图的路径、模型名称和模型(Product对象),该模型将提供给目标视图,用于界面显示。

视图

两个JSP,绑定了CSS样式。

我们在web.xml配置url-pattern来匹配.action ,没有配置 / (所有请求)是因为如果配置了/,而没有配置静态资源过滤,这个CSS也会被拦截,因此这里暂时配置了拦截所有action结尾的请求。

ProductForm.jsp

Add Product Form

Add a product

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

Spring MVC-03循序渐进之Spring MVC(spring boot)

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

ProductDetails.jsp

Save Product

The product has been saved.

Details:
Product Name: ${product.name}
Description: ${product.description}
Price: ${product.price}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

ProductDetail.jsp页面通过模型属性名“product”来访问由SaveProductController传入的Product对象。这里用JSP表达式来显示Product对象的各种属性,后续会详解JSP 的EL表达式。

测试应用

输入URL:

http://localhost:8080/chapter03a/product_input.action

输入相应的数据

提交数据后,url跳转到

http://localhost:8080/chapter03a/product_save.action

View Resolver

上个案例中,页面的跳转通过指定页面的路径来完成的,比如

new ModelAndView("/WEB-INF/jsp/ProductDetails.jsp", "product", product);

1

2

其实,Spring MVC为我们提供了视图解析器,负责解析视图,现在我们来改造下。

在SpringMVC的配置文件中配置视图解析器

1

2

3

4

如上视图解析器前缀和后缀两个属性,这样一来,view的路径就缩短了。 比如仅需要ProductDetails,而无需设置/WEB-INF/jsp/ProductDetails.jsp,视图解析器就会自动增加前缀和后缀。

紧接着我们调整下控制器中的页面跳转

InputProductController 修改为

return new ModelAndView("ProductForm");

1

SaveProductController修改为

return new ModelAndView("ProductDetails", "product", product);

1

2

重新运行测试,结果同上。

总结

本博文是Spring MVC的入门介绍,我们知道了使用SpringMVC,我们无需编写自己的DispatcherServlet,其传统风格的控制器开发方式是实现控制器接口。 从Spring2.5版本开始,Spring提供了基于注解的方式开发控制器,下篇博文介绍。

源码

代码已提交到github

https://github.com/yangshangwei/SpringMvcTutorialArtisan

MVC Servlet Spring

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【Samshing专栏】利用下画线提升用户体验
下一篇:Excel工作簿优化技巧有哪些(excel表格怎么优化)
相关文章