目录
spring MVC
学习网址:
http://c.biancheng.net/spring_mvc/
https://www.w3cschool.cn/spring_mvc_documentation_linesh_translation/
SpringMVC 是一种基于 Java 的实现 MVC 设计模型
的请求驱动类型的轻量级Web框架(三层架构中web层的框架)
,属于 Spring FrameWork 的后续产品,已经融合在 Spring Web Flow 里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用 Spring 进行 WEB 开发时,可以选择使用 Spring 的 Spring MVC 框架或集成其他 MVC 开发框架,如 Struts1 (现在一般不用), Struts2 等。
SpringMVC 已经成为目前最主流的 MVC 框架之一,并且随着 Spring3.0 的发布,全面超越 Struts2, 成为最优秀的 MVC 框架。
它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口
。同时它还支持 RESTful 编程风格的请求。
MVC 是 Model、View 和 Controller 的缩写,分别代表 Web 应用程序(web层)中的 3 种职责。
- 模型:用于存储数据以及处理用户请求的业务逻辑。
- 视图:向控制器提交数据,显示模型中的数据。
- 控制器:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示。
基于 Servlet 的 MVC 模式的具体实现如下。
- 模型:一个或多个 JavaBean 对象,用于存储数据(实体模型,由 JavaBean 类创建)和处理业务逻辑(业务模型,由一般的 Java 类创建)。
- 视图:一个或多个 JSP 页面,向控制器提交数据和为模型提供数据显示,JSP 页面主要使用 HTML 标记和 JavaBean 标记来显示数据。
- 控制器:一个或多个 Servlet 对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的 JavaBean,并将处理结果存放到实体模型 JavaBean 中,输出给视图显示。
MVC中最重要的核心就是控制器,控制器与视图和模型相对独立,它起到一个负责分发请求和返回处理结果的作用,对请求和数据模型的处理一般由JavaBean负责。
Spring MVC 框架中主要的角色划分:
-
前端控制器(DispatcherServlet)
(核心):接收请求,分发请求到相应的控制器(Controller)进行处理,响应结果。相当于转发器,中央处理器,降低了组件之间的耦合性。(1). 不需要进行开发。 (2). 作用:接受请求,响应结果,相当于一个转发器。 (3). 减少了其他组件的耦合度。
-
处理器映射( HandlerMapping):根据请求的URL,找到对应的Handler,由 HandlerMapping 定位到控制器,帮助 DispatcherServlet 找到对应的 Controller 以便分发请求。
(1). 不需要进行开发。 (2). 作用:根据请求的URL查找Handler。
-
处理器适配器( HandlerAdapter):将各种 Controller 适配成 DispatcherServlet 可以使用的Handler,通过特定规则(HandlerAdapter要求的规则)去执行 Handler。
(1). 不需要进行开发。 (2). 作用:按照特定的规则去执行Handler。
-
处理器或页面控制器(Controller / Handler):后端控制器。编写Handler时需要HandlerAdapter的要求去做,这样HandlerAdapter才可以正确执行Handler
Handler是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet控制下对用户请求进行处理,Handler涉及业务需求,所以需要工程师针对用户需求进行开发,最终返回业务数据(1). 需要进行开发。 (2). 要求:必须要按照HandlerAdapter的要求去编写。
-
视图解析器(ViewResolver):进行视图解析,根据逻辑视图名解析成真正的视图View。
(1). 不需要进行开发。 (2). 作用:进行视图解析,根据逻辑视图名解析成真正的视图(View)
-
视图(View ):View是一个接口,实现类支持不同的类型(jsp、html、freemarker、pdf等)
(1). 需要进行开发。 (2). 说明:View是一个接口,实现类支持不同的View类型(jsp、freemaker、pdf.........)
- HandlerInterceptor:Handler / Controller 执行前后拦截器。HandlerInterceptor是个接口,里面包含三个方法:preHandle、postHandle、afterCompletion 分别在 Handler 执行前、执行中、执行完成后执行的三个方法。
- 验证器( Validator)
- 命令对象(Command请求参数绑定到的对象就叫命令对象)
- 表单对象(Form Object提供给表单展示和提交到的对象就叫表单对象)。
从上图可总结出 Spring MVC 的工作流程如下:
- 客户端请求提交到 DispatcherServlet。
- 由 DispatcherServlet 控制器寻找一个或多个 HandlerMapping,通过 HandlerMapping 找到处理请求的 Controller。
- DispatcherServlet 将请求提交到 Controller。
- Controller 调用业务逻辑处理后返回 ModelAndView。
- DispatcherServlet 寻找一个或多个 ViewResolver 视图解析器,找到 ModelAndView 指定的视图。
- 视图负责将结果显示到客户端。
Spring MVC接口:
在上图中包含 4 个 Spring MVC 接口,即 DispatcherServlet、HandlerMapping、Controller 和 ViewResolver。
-
Spring MVC 所有的请求都经过 DispatcherServlet 来统一分发,在 DispatcherServlet 将请求分发给 Controller 之前需要借助 Spring MVC 提供的 HandlerMapping 定位到具体的 Controller。
-
HandlerMapping 接口负责完成客户请求到 Controller 映射。
-
Controller 接口将处理用户请求,这和 Java Servlet 扮演的角色是一致的。一旦 Controller 处理完用户请求,将返回 ModelAndView 对象给 DispatcherServlet 前端控制器,ModelAndView 中包含了模型(Model)和视图(View)。
从宏观角度考虑,DispatcherServlet 是整个 Web 应用的控制器;从微观考虑,Controller 是单个 Http 请求处理过程中的控制器,而 ModelAndView 是 Http 请求过程中返回的模型(Model)和视图(View)。
-
ViewResolver 接口(视图解析器)在 Web 应用中负责查找 View 对象,从而将相应结果渲染给客户。
导包
Spring MVC 程序所需要的 JAR 包,包括 Spring 的 4 个核心 JAR 包、commons-logging 的 JAR 包;
两个与 Web 相关的 JAR 包(spring-web-3.2.13.RELEASE.jar 和 spring-webmvc-3.2.13. RELEASE.jar);
在 Spring MVC 应用中使用注解时添加 spring-aop-3.2.13.RELEASE.jar 包。
前端控制器(DispatcherServlet)
DispatcherServlet 其实就是个 Servlet(它继承自HttpServlet基类),需要 web 应用的 web.xml 配置文件下声明。
前端控制器配置:web.xml
前端控制器在 web.xml 文件中配置
<web-app>
<!-- 部署 DispatcherServlet -->
<servlet>
<servlet-name>example</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 表示容器再启动时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>example</servlet-name>
<!-- 处理所有URL -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
上述 DispatcherServlet 的 servlet 对象 springmvc 初始化时将在应用程序的 WEB-INF 目录下查找一个配置文件,该配置文件的命名规则是“servletName-servlet.xml”,例如 springmvc-servlet.xml。
也可以将 Spring MVC 配置文件存放在应用程序目录中的任何地方,但需要使用 servlet 的 init-param 元素加载配置文件。示例代码如下:
<!-- 部署 DispatcherServlet -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 声明 spring MVC 的配置文件,方便前端控制器访问 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!-- 表示容器再启动时立即加载servlet -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
后端控制器配置:如 springmvc-servlet.xml
spring MVC 的配置文件(需要在 web.xml 核心配置文件中声明):可以在 WEB-INF 目录下,如上述第一种web.xml配置;也可以是其他任意位置,如上述第二种web.xml配置。
创建名为 springmvc-servlet.xml 的配置文件(spring MVC 自己的配置文件):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 自动扫描的包名 -->
<context:component-scan base-package="com.qgl, com.test" ></context:component-scan>
<!-- 默认开启 spring MVC 注解的支持 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 若不使用注解映射(没有上述片段代码的声明),就需要在这里个配置文件中配置控制器类(需要在配置文件中部署映射),如下: -->
<!-- 控制器类 -->
<!-- LoginController控制器类,映射到"/login" -->
<bean name="/login" class="controller.LoginController"/>
<!-- LoginController控制器类,映射到"/register" -->
<bean name="/register" class="controller.RegisterController"/>
<!-- 视图解释类
作用:1、捕获后端控制器的返回值,如"index"
2、解析:在返回值的前后拼接,如"/index.jsp" -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀 -->
<property name="prefix" value="/"></property>
<!-- 后缀 -->
<property name="suffix" value=".jsp"></property><!--可为空,方便实现自已的依据扩展名来选择视图解释类的逻辑 -->
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"></property>
</bean>
</beans>
在SpringMVC的各个组件中,处理器映射器、处理器适配器、视图解析器称为SpringMVC的三大组件。使用<mvc: annotation-driven>自动加载RequestMappingHandlerMapping (处理映射器)和RequestMappingHandlerAdapter (处理适配器),可用在SpringMVC.xml配置文件中使用<mvc: annotation-driven>替代注解处理器和适配器的配置。
注解
传统风格的控制器不仅需要在配置文件中部署映射,而且只能编写一个处理方法,不够灵活。使用基于注解的控制器具有以下两个优点:
- 在基于注解的控制器类中可以编写多个处理方法,进而可以处理多个请求(动作),这就允许将相关的操作编写在同一个控制器类中,从而减少控制器类的数量,方便以后的维护。
- 基于注解的控制器不需要在配置文件中部署映射,仅需要使用 RequestMapping 注释类型注解一个方法进行请求处理。
在 Spring MVC 中最重要的两个注解类型是 Controller 和 RequestMapping。
Controller 注解类型:
@Controller注解表明了一个类是作为控制器的角色而存在的。Spring不要求你去继承任何控制器基类,也不要求你去实现Servlet的那套API。
在 Spring MVC 中使用 org.springframework.stereotype.Controller 注解类型声明某类的实例是一个控制器。
package controller;
import org.springframework.stereotype.Controller;
/**
* “@Controller”表示 IndexController 的实例是一个控制器
*
* @Controller相当于@Controller(@Controller) 或@Controller(value="@Controller")
*/
@Controller
public class IndexController {
// 处理请求的方法
}
在 Spring MVC 中使用扫描机制找到应用中所有基于注解的控制器类,所以,为了让控制器类被 Spring MVC 框架扫描到,需要在配置文件中声明 spring-context,并使用 <context:component-scan/> 元素指定控制器类的基本包(请确保所有控制器类都在基本包及其子包下)。
<!-- 使用扫描机制扫描控制器类,控制器类都在controller包及其子包下 -->
<context:component-scan base-package="controller" />
RequestMapping 注解类型:
在基于注解的控制器类中可以为每个请求编写对应的处理方法。需要使用 org.springframework.web.bind.annotation.RequestMapping 注解类型将请求与处理方法一一对应。
1)方法级别注解:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* “@Controller”表示 IndexController 的实例是一个控制器
*
* @Controller相当于@Controller(@Controller) 或@Controller(value="@Controller")
*/
@Controller
public class IndexController {
@RequestMapping(value = "/index/login")
// 或 @RequestMapping(path = "/index/login"),path与value一样。
public String login() {
/**
* login代表逻辑视图名称,需要根据Spring MVC配置
* 文件中internalResourceViewResolver的前缀和后缀找到对应的物理视图
*/
return "login";
}
@RequestMapping(value = "/index/register")
// 或 @RequestMapping(value = "/index/register"),path与value一样。
public String register() {
return "register";
}
}
上述示例中有两个 RequestMapping 注解语句,它们都作用在处理方法上。注解的 value 属性将请求 URI 映射到方法,value 属性是 RequestMapping 注解的默认属性,如果只有一个 value 属性,则可以省略该属性。
用户可以使用如下 URL 访问 login 方法(请求处理方法),在访问 login 方法之前需要事先在 /WEB-INF/jsp/ 目录下创建 login.jsp。
访问形式:http://localhost:8080/springMVCDemo02/index/login
2)类级别注解:
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/index")
public class IndexController {
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/register")
public String register() {
return "register";
}
}
在类级别注解的情况下,控制器类中的所有方法都将映射为类级别的请求。用户可以使用如下 URL 访问 login 方法。
访问形式:http://localhost:8080/springMVCDemo02/index/login
为了方便维护程序,建议开发者采用类级别注解,将相关处理放在同一个控制器类中。例如,对商品的增、删、改、查处理方法都可以放在 GoodsOperate 控制类中。