当前位置: 首页> 文旅> 旅游 > SpringMVC

SpringMVC

时间:2025/7/11 14:27:17来源:https://blog.csdn.net/weixin_44553952/article/details/139599619 浏览次数:0次

文章目录

  • 1. MVC 架构
  • 2. 基于 Servlet 的 MVC 模式
  • 3. Model 1模式 与 Model 2模式
      • Model 1 模式:
      • Model 2 模式:
  • 4. MVVM 架构
  • 5. Spring MVC
  • 6. SpringMVC 实现步骤
  • 8. Controller 的两种实现方式
  • 9. RestFul风格
  • 10. @ResponseBody
  • 11. 乱码解决
  • 12. 过滤器 VS 拦截器
    • 区别:
  • 参考

1. MVC 架构

MVC 是 Model、View 和 Controller 的缩写,分别代表 Web 应用程序中的 3 种职责。

  • (Model)模型:用于存储数据以及处理用户请求的业务逻辑。

  • (View)视图:向控制器提交数据,显示模型中的数据。

  • (Controller)控制器:根据视图提出的请求判断将请求和数据交给哪个模型处理,将处理后的有关结果交给哪个视图更新显示。

2. 基于 Servlet 的 MVC 模式

模型:一个或多个 JavaBean 对象,用于存储数据(实体模型,由 JavaBean 类创建)和处理业务逻辑(业务模型,由一般的 Java 类创建)。
视图:一个或多个 JSP 页面,向控制器提交数据和为模型提供数据显示,JSP 页面主要使用 HTML 标记和 JavaBean 标记来显示数据。
控制器:一个或多个 Servlet 对象,根据视图提交的请求进行控制,即将请求转发给处理业务逻辑的 JavaBean,并将处理结果存放到实体模型 JavaBean 中,输出给视图显示。

在这里插入图片描述

最典型的MVC就是JSP + servlet + javabean的模式。

在这里插入图片描述

3. Model 1模式 与 Model 2模式

Model 1 模式:

  • 特点

    • 在 Model 1 模式中,整个应用程序的业务逻辑、数据处理和表示层都在同一个组件中。
    • 通常使用 JSP(JavaServer Pages)作为视图层,Java Servlet 用于处理用户请求并在需要时调用 JavaBean(数据模型)来处理业务逻辑。
    • 没有明确的分层结构,所有的逻辑都混合在一起,导致代码难以维护和扩展。
  • 优点

    • 简单,适用于小型应用程序或快速原型开发。
  • 缺点

    • 缺乏分离关注点,使得代码难以理解、测试和维护。
    • 不利于团队合作和代码重用。
    • 可扩展性较差,难以在应用程序规模增大时进行维护。

Model 2 模式:

  • 特点

    • Model 2 模式引入了更严格的分层结构,将应用程序分为模型、视图和控制器三个独立的组件。
    • 通常使用 Servlet 作为控制器层,负责接收用户请求并调用适当的模型进行处理,然后将结果传递给视图层进行呈现。
    • JSP 通常被用作视图层,但与 Model 1 不同的是,JSP 只负责显示数据,不包含业务逻辑。
  • 优点

    • 更好的分离关注点,使代码更易于理解、测试和维护。
    • 支持团队合作和代码重用,因为不同的组件可以独立开发和测试。
    • 更好的可扩展性,允许应用程序在不同的部分进行修改和扩展,而不影响其他部分。
  • 缺点

    • 相对于 Model 1,Model 2 模式需要更多的代码和配置,因此可能增加开发时间和成本。
    • 对于小型应用程序或快速原型开发来说,可能会感到过度复杂。

4. MVVM 架构

把View和Contrller都放在了View层(相当于把Controller一部分逻辑抽离了出来),Model层依然是服务端返回的数据模型。

而ViewModel充当了一个UI适配器的角色,也就是说View中每个UI元素都应该在ViewModel找到与之对应的属性。除此之外,从Controller抽离出来的与UI有关的逻辑都放在了ViewModel中,这样就减轻了Controller的负担。

在这里插入图片描述

  • View层:视图展示。包含UIView以及UIViewController,View层是可以持有ViewModel的。

  • ViewModel层:视图适配器。暴露属性与View元素显示内容或者元素状态一一对应。一般情况下ViewModel暴露的属性建议是readOnly的,至于为什么,我们在实战中会去解释。还有一点,ViewModel层是可以持有Model的。

  • Model层:数据模型与持久化抽象模型。数据模型很好理解,就是从服务器拉回来的JSON数据。而持久化抽象模型暂时放在Model层,是因为MVVM诞生之初就没有对这块进行很细致的描述。按照经验,我们通常把数据库、文件操作封装成Model,并对外提供操作接口。(有些公司把数据存取操作单拎出来一层,称之为DataAdapter层,所以在业内会有很多MVVM的变种,但其本质上都是MVVM)。

  • Binder:MVVM的灵魂。可惜在MVVM这几个英文单词中并没有它的一席之地,它的最主要作用是在View和ViewModel之间做了双向数据绑定。如果MVVM没有Binder,那么它与MVC的差异不是很大。

例子

  1. 创建模型(Model):在这个示例中,我们创建了一个简单的Person类,用于表示人员的数据结构。它有两个属性:firstNamelastName
public class Person {private String firstName;private String lastName;public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}
}
  1. 创建视图(View):我们使用JavaFX创建了一个简单的用户界面。MainView类继承了JavaFX的Application类,并实现了start()方法。在start()方法中,我们创建了两个文本框(TextField)用于输入firstNamelastName,以及一个按钮(Button)用于保存数据。这些UI组件被添加到一个垂直布局(VBox)中,并且展示在舞台(Stage)上。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;public class MainView extends Application {private TextField firstNameField;private TextField lastNameField;private Button saveButton;@Overridepublic void start(Stage primaryStage) {primaryStage.setTitle("MVVM Example");firstNameField = new TextField();lastNameField = new TextField();saveButton = new Button("Save");VBox root = new VBox();root.getChildren().addAll(firstNameField, lastNameField, saveButton);Scene scene = new Scene(root, 300, 200);primaryStage.setScene(scene);primaryStage.show();}
}
  1. 创建视图模型(ViewModel)PersonViewModel类负责连接视图和模型。它包含了firstNamelastName的字符串属性,并且维护了一个保存按钮(saveButton)。在构造函数中,我们将保存按钮传递进来,并且设置了一个监听器,以便在firstNamelastName字段不为空时激活保存按钮。
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.control.Button;public class PersonViewModel {private StringProperty firstName = new SimpleStringProperty();private StringProperty lastName = new SimpleStringProperty();private Button saveButton;public PersonViewModel(Button saveButton) {this.saveButton = saveButton;// 添加监听器,当firstName和lastName不为空时,激活保存按钮saveButton.disableProperty().bind(firstName.isEmpty().or(lastName.isEmpty()));}public StringProperty firstNameProperty() {return firstName;}public StringProperty lastNameProperty() {return lastName;}
}
  1. 连接视图和视图模型:在MainView类中,我们需要实例化视图模型,并将视图和视图模型连接起来。为了实现这一点,我们需要在start()方法中创建一个PersonViewModel对象,并且在按钮点击事件中设置监听器,以便在点击按钮时保存数据。
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;public class MainView extends Application {private TextField firstNameField;private TextField lastNameField;private Button saveButton;@Overridepublic void start(Stage primaryStage) {primaryStage.setTitle("MVVM Example");// 创建视图模型PersonViewModel viewModel = new PersonViewModel(saveButton);firstNameField = new TextField();lastNameField = new TextField();saveButton = new Button("Save");// 绑定视图和视图模型的属性firstNameField.textProperty().bindBidirectional(viewModel.firstNameProperty());lastNameField.textProperty().bindBidirectional(viewModel.lastNameProperty());VBox root = new VBox();root.getChildren().addAll(firstNameField, lastNameField, saveButton);// 设置保存按钮点击事件saveButton.setOnAction(event -> {// 在此处可以执行保存操作,例如将数据传递给模型进行持久化存储System.out.println("Saving: " + viewModel.getFirstName() + " " + viewModel.getLastName());});Scene scene = new Scene(root, 300, 200);primaryStage.setScene(scene);primaryStage.show();}public static void main(String[] args) {launch(args);}
}

5. Spring MVC

在这里插入图片描述

图为SpringMVC的一个较完整的流程图,实线表示SpringMVC框架提供的技术,不需要开发者实现,虚线表示需要开发者实现。

在这里插入图片描述

执行流程

  1. DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。

假设请求的url为 : http://localhost:8080/SpringMVC/hello

如上url拆分成三部分:

http://localhost:8080:服务器域名

SpringMVC:部署在服务器上的web站点

hello:控制器

通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。

  1. HandlerMapping为处理器映射。DispatcherServlet调用HandlerMapping,HandlerMapping根据请求url查找Handler。

  2. HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器,如上url被查找控制器为:hello。

  3. HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等。

  4. HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler。

  5. Handler让具体的Controller执行。

  6. Controller将具体的执行信息返回给HandlerAdapter,如ModelAndView。

  7. HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet。

  8. DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名。

  9. 视图解析器将解析的逻辑视图名传给DispatcherServlet。

  10. DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图。

  11. 最终视图呈现给用户。

6. SpringMVC 实现步骤

在这里插入图片描述

实现步骤:

  1. 新建一个web项目

  2. 导入相关jar包

  3. 编写web.xml , 注册DispatcherServlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!--1.注册servlet--><servlet><servlet-name>SpringMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--通过初始化参数指定SpringMVC配置文件的位置,进行关联--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc-servlet.xml</param-value></init-param><!-- 启动顺序,数字越小,启动越早 --><load-on-startup>1</load-on-startup></servlet><!--所有请求都会被springmvc拦截 --><servlet-mapping><servlet-name>SpringMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>/*
注意/ 和 /* 的区别:
< url-pattern > / </ url-pattern > 不会匹配到.jsp, 只针对我们编写的请求;
即:.jsp 不会进入spring的 DispatcherServlet类 。< url-pattern > /* </ url-pattern > 会匹配 *.jsp,
会出现返回 jsp视图 时再次进入spring的DispatcherServlet 类,
导致找不到对应的controller所以报404错。
  1. 编写springmvc配置文件(在resource目录下添加springmvc-servlet.xml配置文件, 配置的形式与Spring容器配置基本类似,为了支持基于注解的IOC,设置了自动扫描包的功能,具体配置信息如下:)
<?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:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 自动扫描包,让指定包下的注解生效,由IOC容器统一管理 --><context:component-scan base-package="com.github.subei.controller"/><!-- 让Spring MVC不处理静态资源 --><mvc:default-servlet-handler /><!--支持mvc注解驱动在spring中一般采用@RequestMapping注解来完成映射关系要想使@RequestMapping注解生效必须向上下文中注册DefaultAnnotationHandlerMapping和一个AnnotationMethodHandlerAdapter实例这两个实例分别在类级别和方法级别处理。而annotation-driven配置帮助我们自动完成上述两个实例的注入。--><mvc:annotation-driven /><!-- 视图解析器 --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"id="internalResourceViewResolver"><!-- 前缀 --><property name="prefix" value="/WEB-INF/jsp/" /><!-- 后缀 --><property name="suffix" value=".jsp" /></bean></beans>
  1. 接下来就是去创建对应的控制类 , controller
package com.github.subei.controller;import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
@RequestMapping("/HelloController")
public class HelloController {// 真实访问地址 : 项目名/HelloController/hello@RequestMapping("/hello")public String sayHello(Model model){// 向模型中添加属性msg与值,可以在JSP页面中取出并渲染model.addAttribute("msg","hello,SpringMVC");// web-inf/jsp/hello.jspreturn "hello";}
}
  1. 最后完善前端视图和controller之间的对应, jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>SpringMVC</title>
</head>
<body>
${msg}
</body>
</html>
  1. 测试运行调试.

使用springMVC必须配置的三大件:

  • 处理器映射器、处理器适配器、视图解析器
  • 通常,只需要手动配置视图解析器,而处理器映射器处理器适配器只需要开启注解驱动即可,而省去了大段的xml配置

8. Controller 的两种实现方式

  1. 实现 Controller 接口并重写handleRequest() 方法,并在springmvc-servlet.xml 添加 该控制器为bean,以及其访问路径;

  2. 使用注解,@Controller, @RequestMapping(“/path”)等

9. RestFul风格

在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !

Restful风格是一种基于标准HTTP方法来设计Web服务的架构风格。它强调使用HTTP协议的各种特性来实现资源的增删改查(CRUD操作),以及对资源的状态转换。下面是Restful风格的一些主要特点:

  1. 资源(Resources): 在Restful架构中,一切皆资源。资源可以是任何事物,例如用户、商品、订单等等。每个资源都有一个唯一的标识符(URI)来进行访问。

  2. HTTP方法(HTTP Methods): Restful风格使用HTTP方法来定义操作资源的行为。常用的HTTP方法包括GET(获取资源)、POST(创建资源)、PUT(更新资源)、DELETE(删除资源)等。

使用RESTful操作资源 :可以通过不同的请求方式来实现不同的效果!如下:请求地址一样,但是功能可以不同!

  • http://127.0.0.1/item/1 查询,GET

  • http://127.0.0.1/item 新增,POST

  • http://127.0.0.1/item 更新,PUT

  • http://127.0.0.1/item/1 删除,DELETE

  1. 表述(Representation): 资源的表述是指客户端与服务器之间交换的数据格式。通常使用JSON或XML格式来表示资源的状态。@ResponseBody

  2. 无状态(Stateless): Restful架构是无状态的,即服务器不会保存客户端的状态信息。每个请求都包含足够的信息,使服务器能够理解并处理请求。

  3. 统一接口(Uniform Interface): Restful架构通过使用统一的接口来简化系统架构,并提高系统的可见性和可伸缩性。这包括使用标准的HTTP方法、URI和媒体类型。

  4. 资源链接(Resource Linking): Restful架构允许在资源之间建立链接关系,以支持导航和发现。

  5. 无连接(Stateless): Restful架构是无连接的,即客户端的每个请求都包含足够的信息,使服务器能够理解并处理请求,而不需要依赖之前的请求。

10. @ResponseBody

由于@ResponseBody注解,(return str;)这里会将str转成json格式返回;十分方便

注意:使用json记得处理乱码问题

在类上直接使用 @RestController ,这样子,里面所有的方法都只会返回 json 字符串了,不用再每一个都添加@ResponseBody !

11. 乱码解决

  1. 在 web.xml 配置字符编码过滤器,以确保所有请求和响应都使用正确的字符编码
<filter><filter-name>encodingFilter</filter-name><filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class><init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param><init-param><param-name>forceEncoding</param-name><param-value>true</param-value></init-param>
</filter>
<filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
  1. 自定义过滤器类实现 Filter 接口,重写doFilter() 方法
import javax.servlet.*;
import java.io.IOException;public class EncodingFilter implements Filter {private String encoding;@Overridepublic void init(FilterConfig filterConfig) throws ServletException {encoding = filterConfig.getInitParameter("encoding");if (encoding == null) {encoding = "UTF-8"; // 默认使用UTF-8编码}}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {request.setCharacterEncoding(encoding);response.setCharacterEncoding(encoding);chain.doFilter(request, response);}@Overridepublic void destroy() {// 过滤器销毁时的处理}
}

12. 过滤器 VS 拦截器

区别:

过滤器(Filter)和拦截器(Interceptor)是在 Java Web 开发中用于实现对请求和响应进行处理的两种不同机制。

  1. 作用层次不同
  • 过滤器是基于 Servlet 规范的,工作在 Servlet 层面,可以在请求进入 Servlet 之前或响应离开 Servlet 之后进行处理。
  • 拦截器是 Spring 框架提供的,工作在 Spring MVC 层面,用于对控制器的请求进行预处理和后处理。
  1. 所属技术框架不同
  • 过滤器是 Servlet 规范中的一部分,属于 Java EE 的一部分,而且不依赖于任何特定的框架。
  • 拦截器是 Spring MVC 框架提供的,用于在 Spring MVC 控制器中进行请求处理的一个机制。
  1. 调用方式不同
  • 过滤器通过 Servlet 容器的 doFilter() 方法调用,直接在 Servlet 的请求处理链中执行。
  • 拦截器则是由 Spring MVC 框架控制器所管理的,通过AOP(面向切面编程)的思想,与控制器方法进行交互。
  1. 灵活性不同
  • 过滤器的灵活性相对较低,无法直接访问 Spring 托管的 Bean,通常用于请求的预处理和后处理。

    过滤器的设计初衷是为了处理 Servlet 请求和响应,它们并不属于 Spring 容器的管理范围,因此在过滤器中无法直接通过 Spring 上下文来访问 Spring 托管的 Bean。

  • 拦截器则可以方便地访问 Spring 托管的 Bean,可以在请求处理前后执行更加灵活的逻辑,例如验证用户权限、记录日志等。

  1. 作用范围不同
  • 过滤器作用于 Servlet 的请求处理链中,可以对所有的请求进行拦截和处理。
  • 拦截器则主要用于对 Spring MVC 控制器的请求进行处理,因此仅作用于经过 Spring MVC 控制器的请求。

参考

Spring MVC入门学习目录 - subeiLY - 博客园

关键字:SpringMVC

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: