【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);
    }
}

总结

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

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

相关推荐
weixin_SAG3 分钟前
21天掌握javaweb-->第19天:Spring Boot后端优化与部署
java·spring boot·后端
m0_748247556 分钟前
SpringMVC跨域问题解决方案
java
Elcker7 分钟前
KOI技术-事件驱动编程(Sping后端)
java·spring·架构
GitNohup9 分钟前
Spring boot处理跨域问题
java·spring boot·跨域
Just_Paranoid21 分钟前
使用 IDE生成 Java Doc
java·开发语言·ide
西海天际蔚蓝36 分钟前
递归查询全量分页数据问题
java
俎树振1 小时前
深入理解与优化Java二维数组:从定义到性能提升的全面指南
java·算法
DARLING Zero two♡1 小时前
【优选算法】Sliding-Chakra:滑动窗口的算法流(上)
java·开发语言·数据结构·c++·算法
love静思冥想1 小时前
Apache Commons ThreadUtils 的使用与优化
java·线程池优化
君败红颜1 小时前
Apache Commons Pool2—Java对象池的利器
java·开发语言·apache