【SpringMVC】一个你说不出它哪里好,又说不出哪里不好的框架 !

一、先思考几个问题,以便于更好的了解 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 都要经历那些流程?(完整流程)

  1. 客户端发起请求: 用户通过浏览器或其他客户端向服务器发起HTTP请求。

    你在浏览器中输入网址,发起了一个请求。

  2. 请求到达前端控制器(DispatcherServlet):** 请求首先被DispatcherServlet接收,它是SpringMVC的前端控制器,是整个流程的起点。

    请求到达了SpringMVC的 总指挥(DispatcherServlet)。

  3. 处理器映射器(Handler Mapping)确定处理器: DispatcherServlet使用处理器映射器来确定请求应该由哪个控制器(Handler)处理。处理器映射器根据配置或注解找到匹配的处理器。

    DispatcherServlet 找到了一个处理器(Controller)来处理你的请求。

  4. 控制器处理请求: 找到匹配的控制器后,控制器执行相应的方法来处理请求。这个方法可能包含业务逻辑、数据处理等。

    这个处理器(Controller)执行一些操作,可能涉及到数据库查询、数据处理等。

  5. 模型处理数据: 控制器可以与模型(Model)交互,进行数据处理和业务逻辑。模型通常包含应用程序的数据和业务规则。

    处理器(Controller)把需要显示的数据交给了一个"视图"(View)。

  6. 视图解析器(View Resolver)确定视图: 控制器处理完请求后,它返回一个逻辑视图的名称。视图解析器将逻辑视图名称解析为实际的视图(View),这可以是JSP、Thymeleaf等。

    视图(View)的任务是把数据渲染成最终的页面内容。

  7. 视图渲染: 视图负责将模型中的数据渲染到视图中,生成最终的响应内容。这可以是HTML、JSON等格式。

    最终,渲染好的页面通过 DispatcherServlet 返回给你的浏览器。

  8. 响应发送到客户端: 渲染后的视图作为响应发送回DispatcherServlet。

    返回 ing 。

  9. 响应返回客户端: 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 中是:

  1. 组件扫描: Spring Boot默认会扫描主应用程序类所在的包及其子包,无需额外配置。如果你的控制器类位于主应用程序类的包或其子包下,Spring Boot将自动扫描并注册这些组件。

  2. 视图解析器: Spring Boot使用约定大于配置的原则,默认的视图解析器会解析到/src/main/resources/templates/目录下。无需手动配置,可以直接在这个目录下放置Thymeleaf、Freemarker、Mustache等模板引擎支持的模板文件。

  3. 拦截器: Spring Boot允许通过实现HandlerInterceptor接口或扩展HandlerInterceptorAdapter类来创建拦截器。一旦创建了拦截器类,Spring Boot会自动注册它们,无需显式配置。

    java 复制代码
    @Component
    public class SampleInterceptor implements HandlerInterceptor {
        // 拦截器的实现
    }
  4. 静态资源处理: Spring Boot默认的静态资源路径是/static/public/resources/META-INF/resources。无需在spring-mvc.xml中额外配置,只需将静态资源放置在这些目录下即可。

  5. 注解驱动: Spring Boot自动开启注解驱动,无需手动配置。

  6. 默认的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);
    }
}

总结

一定要多思考,如果人永远待在舒适圈的话,人永远不会成长。共勉

觉得作者写的不错的,值得你们借鉴的话,就请点一个免费的赞吧!这个对我来说真的很重要。૮(˶ᵔ ᵕ ᵔ˶)ა

相关推荐
咩咩啃树皮2 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
鱟鲥鳚3 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
大模型码小白4 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司5 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地6 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
wuqingshun3141596 小时前
TCP超时重传机制是为了解决什么问题?
java
莫逸风8 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
隔窗听雨眠8 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
z123456789869 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin52112310 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python