一、先思考几个问题,以便于更好的了解 SpringMVC
1、什么是MVC架构,它的核心思想是什么?
MVC(模型-视图-控制器)是一种软件设计模式,将应用程序分为三个部分,分别是模型(负责处理数据和业务逻辑)、视图(负责显示用户界面)、控制器(负责处理用户输入和管理流程)。MVC的核心思想是分离关注点,使得各部分可以独立开发和维护。
2、在没有MVC之前,Web应用是如何组织和开发的?存在哪些问题?
在没有MVC之前,Web应用通常采用紧密耦合的设计,HTML、业务逻辑和数据处理混合在一起,导致难以维护和扩展。
3、为什么MVC成为一种流行的设计模式,而且在Web开发中得到广泛应用?MVC架构解决了那些方面的问题?
MVC架构的引入解决了分离关注点、提高可维护性、降低耦合度的问题。它使得开发者可以更好地组织代码,降低了变更一个部分对其他部分的影响,提高了代码的可重用性和可测试性。
4、所以什么是 SpringMVC ?
SpringMVC是Spring框架中的一个模块,用于支持基于模型-视图-控制器(MVC)设计模式的Web应用程序开发。它提供了一种结构化的方式来组织和开发Web应用,使得代码更加模块化、可维护,并且易于扩展。SpringMVC是建立在核心Spring框架之上的,因此可以很好地集成Spring的其他模块。
二、一个请求进入SpringMVC 都要经历那些流程?(完整流程)
-
客户端发起请求: 用户通过浏览器或其他客户端向服务器发起HTTP请求。
你在浏览器中输入网址,发起了一个请求。
-
请求到达前端控制器(DispatcherServlet):** 请求首先被DispatcherServlet接收,它是SpringMVC的前端控制器,是整个流程的起点。
请求到达了SpringMVC的 总指挥(DispatcherServlet)。
-
处理器映射器(Handler Mapping)确定处理器: DispatcherServlet使用处理器映射器来确定请求应该由哪个控制器(Handler)处理。处理器映射器根据配置或注解找到匹配的处理器。
DispatcherServlet 找到了一个处理器(Controller)来处理你的请求。
-
控制器处理请求: 找到匹配的控制器后,控制器执行相应的方法来处理请求。这个方法可能包含业务逻辑、数据处理等。
这个处理器(Controller)执行一些操作,可能涉及到数据库查询、数据处理等。
-
模型处理数据: 控制器可以与模型(Model)交互,进行数据处理和业务逻辑。模型通常包含应用程序的数据和业务规则。
处理器(Controller)把需要显示的数据交给了一个"视图"(View)。
-
视图解析器(View Resolver)确定视图: 控制器处理完请求后,它返回一个逻辑视图的名称。视图解析器将逻辑视图名称解析为实际的视图(View),这可以是JSP、Thymeleaf等。
视图(View)的任务是把数据渲染成最终的页面内容。
-
视图渲染: 视图负责将模型中的数据渲染到视图中,生成最终的响应内容。这可以是HTML、JSON等格式。
最终,渲染好的页面通过 DispatcherServlet 返回给你的浏览器。
-
响应发送到客户端: 渲染后的视图作为响应发送回DispatcherServlet。
返回 ing 。
-
响应返回客户端: DispatcherServlet将最终的响应返回给客户端,完成了整个请求-响应的循环。
好了 , 你在浏览器上看到了页面的内容。
这张图借鉴了 Java 全栈知识体系,非常的契合。
三、SpringMVC 快速入门 (单独引入和SpringBoot两种方式)
3.1 导入依赖
单独引入
xml
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
SpringBoot :Spring Boot自动启用Spring MVC,只需确保在项目中引入了spring-boot-starter-web
依赖即可。
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3.2 配置前端控制器 web.xml
在一个MVC框架中,首要任务是有效地接收并处理请求。
为了实现这一目标,框架通常会设计一个前端控制器。
这个前端控制器位于框架的最前沿,负责接收所有进入系统的请求。
选择在Servlet或者Filter中实现这一前端控制器。
这个前端控制器的任务不仅仅是作为请求的第一站,更是核心调度管理的关键组件。
这样,它在整个MVC框架中既是前端的门卫,又是核心的调度者。
在Spring MVC中,前端控制器是由DispatcherServlet
来实现的。
在 web.xml
文件中 :
xml
<!-- web.xml -->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc.xml</param-value> <!-- 配置Spring MVC的XML文件位置 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/</url-pattern> <!-- 映射到所有请求 -->
</servlet-mapping>
在 SpringBoot 中传统的web.xml
进行Servlet配置的方式已经不需要了。Spring Boot提供了默认的Servlet配置,并通过自动检测和配置,使得大部分情况下无需手动干预。(默认不用配置)
yml
spring:
mvc:
servlet:
load-on-startup: 1
url-pattern: /
3.3 配置与MVC框架相关的一些设置 spring-mvc.xml
xml
<!-- spring-mvc.xml -->
<!-- 配置组件扫描,指定需要被Spring容器管理的包 -->
<context:component-scan base-package="com.example.controller" />
<!-- 配置视图解析器 -->
<!-- 如果是jsp项目的话 这块应该配置它的后缀和前缀 -->
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultViews">
<list>
<!-- 配置 JSON 视图 -->
<bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" />
</list>
</property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="com.example.interceptor.SampleInterceptor" />
</mvc:interceptors>
<!-- 配置静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/" />
<!-- 开启注解驱动,启用Spring MVC注解支持 -->
<mvc:annotation-driven />
<!-- 配置默认的Servlet处理 -->
<mvc:default-servlet-handler />
这些配置在 SpringaBoot 中是:
-
组件扫描: Spring Boot默认会扫描主应用程序类所在的包及其子包,无需额外配置。如果你的控制器类位于主应用程序类的包或其子包下,Spring Boot将自动扫描并注册这些组件。
-
视图解析器: Spring Boot使用约定大于配置的原则,默认的视图解析器会解析到
/src/main/resources/templates/
目录下。无需手动配置,可以直接在这个目录下放置Thymeleaf、Freemarker、Mustache等模板引擎支持的模板文件。 -
拦截器: Spring Boot允许通过实现
HandlerInterceptor
接口或扩展HandlerInterceptorAdapter
类来创建拦截器。一旦创建了拦截器类,Spring Boot会自动注册它们,无需显式配置。java@Component public class SampleInterceptor implements HandlerInterceptor { // 拦截器的实现 }
-
静态资源处理: Spring Boot默认的静态资源路径是
/static
、/public
、/resources
和/META-INF/resources
。无需在spring-mvc.xml
中额外配置,只需将静态资源放置在这些目录下即可。 -
注解驱动: Spring Boot自动开启注解驱动,无需手动配置。
-
默认的Servlet处理: Spring Boot会自动配置
DefaultServletHttpRequestHandler
来处理默认的Servlet请求,无需显式配置。
3.4 后端控制器 Controller
这就是我们熟悉的 Restful 风格的 Controller
java
@Controller
@RequestMapping("/user")
public class UserController {
@RequestMapping("/login")
public String getInfo() {
System.out.println("...");
return "login";
}
}
四、在Controller接收请求参数的几种方式
4.1 基本类型 接收参数
java
@Controller
public class MyController {
/**
* 示例方法,演示Spring MVC基本类型传参和日期格式化
*
* @param i 整数参数
* @param l 长整数参数
* @param b 布尔参数
* @param d 日期参数,使用@DateTimeFormat自定义格式
* @return 空字符串
*/
@RequestMapping("/login")
public String getInfo(@RequestParam Integer i,
@RequestParam Long l,
@RequestParam Boolean b,
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam Date d) {
// 在这里处理你的业务逻辑
return "login"; // 返回重定向到首页的视图名 我们定义的是json
}
}
SpringBoot中 假如说我们在/src/main/resources/templates/
创建一个Thymeleaf模板 login.html
html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login Page</title>
</head>
<body>
<h2>Login Page</h2>
<form action="/login" method="post">
<label>Integer Parameter: <input type="text" name="i" /></label><br/>
<label>Long Parameter: <input type="text" name="l" /></label><br/>
<label>Boolean Parameter: <input type="checkbox" name="b" /></label><br/>
<label>Date Parameter: <input type="text" name="d" placeholder="yyyy-MM-dd HH:mm:ss" /></label><br/>
<button type="submit">Submit</button>
</form>
</body>
</html>
那么我们的
kotlin
return "login"; // 返回Thymeleaf模板的名称,对应于login.html
4.2 实体类型 接收参数
我们创造一个 User
对象
java
public class User {
private Integer id;
private String username;
private String password;
// 其他属性和方法...
// 省略构造函数和getter/setter方法
}
java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ModelAttribute;
@Controller
public class LoginController {
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String showLoginPage(User user,Model model) {
// 在GET请求时,向模型添加一个空的User对象,用于渲染表单
model.addAttribute("user", user);
return "login"; // 返回Thymeleaf模板的名称,对应于login.html
}
@PostMapping("/login")
public String processLogin(@ModelAttribute User user, Model model) {
// 在POST请求时,user对象将被自动填充从表单传递过来的参数
// 在实际应用中,这里可以处理接收到的User对象,进行业务逻辑处理
// 将接收到的User对象传递给模板,以便在页面显示
model.addAttribute("user", user);
return "login"; // 返回Thymeleaf模板的名称,对应于login.html
}
// RESTful API 的请求的时候 可以用 @RequestBody
@PostMapping("/user")
public String createUser(@RequestBody User user) {
// 处理接收到的 User 对象
// ...
return "User created successfully";
}
}
4.3 数组类型 接收参数
请求: POST /processArray?numbers=1&numbers=2&numbers=3
处理 和 收参:
java
@Controller
public class MyController {
@PostMapping("/processArray")
@ResponseBody
public String processArray(@RequestParam("numbers") int[] numbers) {
// 在这里处理接收到的数组参数
// 可以进行业务逻辑处理,例如计算数组的总和、平均值等
StringBuilder result = new StringBuilder("Received array: ");
for (int num : numbers) {
result.append(num).append(" ");
}
return result.toString();
}
}
4.4 集合类型 接收参数
请求: POST /processList?items=apple&items=orange&items=banana
处理 和 收参:
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
@Controller
public class MyController {
@PostMapping("/processList")
@ResponseBody
public String processList(@RequestParam("items") List<String> items) {
// 在这里处理接收到的集合参数
// 可以进行业务逻辑处理,例如遍历集合、对集合进行操作等
StringBuilder result = new StringBuilder("Received list: ");
for (String item : items) {
result.append(item).append(" ");
}
return result.toString();
}
}
4.5 路径 接收参数
请求: GET /user/123
处理 和 收参:
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@GetMapping("/user/{userId}")
@ResponseBody
public String getUserById(@PathVariable Long userId) {
// 在这里处理接收到的路径参数
// 可以进行业务逻辑处理,例如根据用户ID查询用户信息等
return "User ID: " + userId;
}
}
五、请求转发 和 重定向
5.1 请求转发
在Spring MVC中,请求转发是通过将请求转发到另一个控制器或视图来实现的。Spring提供了多种方式来执行请求转发,其中最常见的两种是使用forward:
前缀进行转发和使用RequestDispatcher
进行转发。
使用 forward: 前缀进行转发
在控制器中,你可以使用 forward:
前缀指定要转发到的路径。
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyController {
@GetMapping("/original")
public String originalPage() {
// 处理原始请求的逻辑
return "originalPage";
}
@GetMapping("/forward")
public String forwardPage() {
// 转发到原始请求的处理方法
return "forward:/original";
}
}
使用 RequestDispatcher 进行转发
另一种方式是通过 HttpServletRequest
对象的 getRequestDispatcher
方法获取 RequestDispatcher
并进行转发。
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
@Controller
public class MyController {
@GetMapping("/original")
public String originalPage() {
// 处理原始请求的逻辑
return "originalPage";
}
@GetMapping("/forward")
public String forwardPage(HttpServletRequest request) {
// 使用 RequestDispatcher 进行转发
RequestDispatcher dispatcher = request.getRequestDispatcher("/original");
try {
dispatcher.forward(request, null);
} catch (Exception e) {
// 处理异常
e.printStackTrace();
}
return null; // 返回 null,告诉 Spring MVC 不要再继续处理
}
}
5.2 重定向
在 Spring MVC 中,重定向是通过将请求重定向到另一个路径或URL来实现的。Spring提供了两种主要的方式来执行重定向:使用 redirect:
前缀进行重定向和使用 RedirectView
类。
使用 redirect: 前缀进行重定向
在控制器中,你可以使用 redirect:
前缀指定要重定向到的路径或URL。
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MyController {
@GetMapping("/original")
public String originalPage() {
// 处理原始请求的逻辑
return "originalPage";
}
@GetMapping("/redirect")
public String redirectToOriginal() {
// 重定向到原始请求的处理方法
return "redirect:/original";
}
}
使用 RedirectView 进行重定向
另一种方式是通过 RedirectView
类实现重定向。
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.view.RedirectView;
@Controller
public class MyController {
@GetMapping("/original")
public String originalPage() {
// 处理原始请求的逻辑
return "originalPage";
}
@GetMapping("/redirect")
public RedirectView redirectToOriginal() {
// 使用 RedirectView 进行重定向
RedirectView redirectView = new RedirectView("/original");
redirectView.setExposeModelAttributes(false); // 不暴露模型属性
return redirectView;
}
}
5.3 SpringBoot 中 转发 和 重定向
最近碰见一个需要后端重定向的一个需求,需要记录一下。
java
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
public class MyController {
/**
* 通过 HttpServletResponse 进行重定向到指定的 URL。
*
* @param response HttpServletResponse 对象,用于发送重定向响应给客户端
* @param url 要重定向到的 URL
* @throws IOException 可能的 IO 异常
*/
@GetMapping("/redirect")
public void forward(HttpServletResponse response, String url) throws IOException {
response.sendRedirect(url);
}
}
总结
一定要多思考,如果人永远待在舒适圈的话,人永远不会成长。共勉
觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა