概述
Spring MVC(Model-View-Controller,模型-视图-控制器)是Spring框架的一部分,用于构建基于Java的Web应用程序。它遵循MVC设计模式,分离了应用程序的不同方面(输入逻辑、业务逻辑和UI逻辑),从而实现松耦合和模块化。
主要组件
主控:DispatcherServlet 前端控制器
三大组件:Handler Mapping -> HandlerAdapter -> View Resolver
-
DispatcherServlet 前端控制器:
- 核心组件,是前端控制器(Front Controller)模式的实现。
- 接收所有的HTTP请求,并将其分发给适当的处理器(Controller)。
-
Handler Mapping 处理器映射器:
- 将请求映射到具体的处理器(Controller)。
- 可以基于URL、注解、请求参数等进行映射。
-
HandlerAdapter 处理器适配器
-
Controller:
- 处理请求的具体组件。
- 通常是一个带有特定注解(如
@Controller
、@RequestMapping
)的类或方法。 - 从Model中获取数据并将其返回给视图(View)。
-
ModelAndView:
- 包含模型数据和视图信息的对象。
- Controller处理完请求后,返回一个ModelAndView对象,交给DispatcherServlet。
-
View Resolver 视图解析器:
- 根据逻辑视图名解析实际的视图实现。
- 常见的视图技术有JSP、Thymeleaf、FreeMarker等。
-
View:
- 负责呈现最终结果给用户。
- 使用模型数据生成响应内容。
HandlerAdapter处理器适配器中的设计模式
在Spring MVC中,HandlerAdapter
主要使用了以下设计模式:
1. 适配器模式(Adapter Pattern)
定义:适配器模式用于将一个接口转换为客户端期望的另一个接口,使得原本由于接口不兼容而无法一起工作的类能够一起工作。
在Spring MVC中的应用:
HandlerAdapter
接口是适配器模式的典型例子。Spring MVC通过HandlerAdapter
将不同类型的处理器(如Controller)适配为统一的处理方式。- Spring MVC支持多种处理器类型,如传统的Controller接口实现、注解驱动的控制器等。每种处理器类型都有相应的
HandlerAdapter
实现,将其转换为DispatcherServlet
可以处理的格式。 - 例如,
RequestMappingHandlerAdapter
适配了基于注解的控制器,SimpleControllerHandlerAdapter
适配了传统的实现Controller
接口的控制器。
2. 策略模式(Strategy Pattern)
定义:策略模式定义了一系列算法或行为,并将它们封装起来,使它们可以互换。策略模式让算法独立于使用它的客户端变化。
在Spring MVC中的应用:
HandlerAdapter
接口本身体现了策略模式。不同的HandlerAdapter
实现了不同的策略,处理不同类型的请求处理器。DispatcherServlet
作为客户端,使用不同的HandlerAdapter
策略来处理不同的控制器类型。这使得Spring MVC能够灵活地扩展和适应新的控制器类型,而无需修改核心代码。
3. 工厂模式(Factory Pattern)
定义:工厂模式用于创建对象,而无需指定创建对象的具体类。工厂模式通过定义一个创建对象的接口,将实际创建工作推迟到子类中。
在Spring MVC中的应用:
- Spring的应用上下文(ApplicationContext)和Web上下文(WebApplicationContext)使用了工厂模式来管理和创建
HandlerAdapter
实例。 - 在配置Spring MVC时,可以通过配置文件或注解声明哪些
HandlerAdapter
应该被创建和使用,Spring框架会负责实际的对象创建和依赖注入。
具体示例
假设有一个简单的基于注解的控制器:
java
@Controller
public class MyController {
@RequestMapping("/hello")
public String handleRequest() {
return "hello";
}
}
对于上述控制器,Spring MVC的工作流程如下:
- DispatcherServlet接收请求。
- 使用HandlerMapping 找到相应的处理器(即
MyController
)。 - DispatcherServlet 使用适当的HandlerAdapter (如
RequestMappingHandlerAdapter
)来调用处理器。 RequestMappingHandlerAdapter
将MyController
的请求处理方法适配为通用的处理方式,返回视图名。
通过适配器模式,Spring MVC能够统一处理不同类型的控制器,使得框架更加灵活和可扩展。
工作流程
执行时序图
- 客户端发送HTTP请求。
- DispatcherServlet接收请求。
- DispatcherServlet通过Handler Mapping找到适当的Controller。
- Controller处理请求,操作Model,生成ModelAndView对象。
- DispatcherServlet通过View Resolver解析逻辑视图名,找到实际的View实现。
- View使用Model数据生成响应内容,返回给客户端。
执行原理图
核心注解
- @Controller: 标识一个类为Controller。
- @RequestMapping: 用于映射请求到具体的处理器方法。
- @GetMapping, @PostMapping, @PutMapping, @DeleteMapping: 更具体的请求映射注解。
- @RequestParam: 绑定请求参数到方法参数。
- @PathVariable: 绑定URL模板变量到方法参数。
- @ModelAttribute: 绑定请求参数到模型对象。
示例代码
java
@Controller
public class HelloController {
@RequestMapping("/hello")
public ModelAndView hello(@RequestParam("name") String name) {
ModelAndView mav = new ModelAndView();
mav.setViewName("hello");
mav.addObject("message", "Hello, " + name);
return mav;
}
}
配置文件示例(XML)
xml
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="com.example.HelloController" />
</beans>
优点
- 松耦合: 通过MVC模式分离关注点。
- 灵活性: 支持多种视图技术和模板引擎。
- 易扩展: 可以通过配置和注解轻松扩展功能。
- 集成性: 与Spring生态系统的其他部分无缝集成,如Spring Security、Spring Data等。
Spring MVC是一个强大且灵活的Web框架,适用于从小型到大型的Web应用开发。通过它,开发者可以快速构建、测试和维护高质量的Java Web应用程序。
比较传统方法
使用传统的Servlet和JSP技术来改写示例代码。传统方法下,我们需要手动处理请求,管理视图以及传递数据。以下是相应的实现:
目录结构
|-- src
| |-- main
| |-- java
| | |-- com
| | |-- example
| | |-- HelloServlet.java
| |-- webapp
| |-- WEB-INF
| |-- views
| | |-- hello.jsp
| |-- web.xml
HelloServlet.java
java
package com.example;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getParameter("name");
if (name == null || name.isEmpty()) {
name = "World";
}
request.setAttribute("message", "Hello, " + name);
request.getRequestDispatcher("/WEB-INF/views/hello.jsp").forward(request, response);
}
}
hello.jsp
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<h1>${message}</h1>
</body>
</html>
web.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
工作流程
- 客户端发送请求 :用户在浏览器中输入
http://localhost:8080/your-app-context/hello?name=John
。 - Servlet接收请求 :
HelloServlet
的doGet
方法处理这个请求。 - 参数处理 :Servlet从请求中获取参数
name
,如果没有传递参数,默认值为"World"。 - 设置请求属性 :Servlet将生成的消息作为请求属性
message
存储。 - 请求转发 :Servlet使用
RequestDispatcher
将请求转发到hello.jsp
。 - 视图生成 :
hello.jsp
使用请求属性message
生成响应内容并返回给客户端。
解释
- Servlet:代替了Spring MVC的Controller,用于处理HTTP请求。
- RequestDispatcher:用于将请求转发到JSP页面,类似于Spring MVC中的View Resolver。
- JSP:负责生成最终的HTML响应,类似于Spring MVC中的视图。
这种方法没有Spring MVC那样的模块化和灵活性,但它展示了在没有Spring MVC框架支持下,如何使用Servlet和JSP技术处理请求和生成视图。