当前位置: 首页 > news >正文

SpringMVC框架

目录

一、三层架构与MVC模型

1.1 三层架构体系

1.2 MVC设计模式

二、SpringMVC入门案例

2.1 概述

2.1.1 SpringMVC的概述

2.1.2 SpringMVC在三层架构中的位置

2.1.3 SpringMVC和Struts2框架的对比

2.2 SpringMVC的入门程序

2.3 执行流程解析

2.3.1 执行流程

2.3.2 组件分析

2.4 RequestMapping注解

三、请求参数的绑定

3.1 请求参数的绑定说明

3.1.1 绑定机制

3.1.2 支持的数据类型

3.1.3 基本数据类型和字符串类型

3.1.4 实体类型(JavaBean)

3.1.5 给集合属性数据封装

3.2 示例

3.3 中文乱码解决

3.4 自定义类型转换器(日期)

3.4.1 使用DateTimeFormat注解

3.4.2 自定义类型转换器(实现Converter的接口)

四、总结与扩展


一、三层架构与MVC模型

1.1 三层架构体系

在B/S架构开发中,分层设计是提升代码可维护性的核心思想。三层架构将系统划分为三个逻辑层:

  • 表现层(WEB层)
    负责与用户交互,接收请求并返回响应。采用MVC设计模式实现,常见技术:SpringMVC、Struts2。

  • 业务层(Service层)
    处理核心业务逻辑(如订单处理、权限校验),协调数据层和表现层。
    典型实现:Spring框架管理的Service组件。

  • 持久层(DAO层)
    操作数据库,提供数据存取服务。常用技术:MyBatis、Hibernate、JPA。

架构优势:解耦、复用性高、易于协作开发。

1.2 MVC设计模式

MVC(Model View Controller)模型视图控制器,实现职责分离:

  • Model(模型)
    数据模型,JavaBean的类,用来进行数据封装。

  • View(视图)
    展示数据(JSP、Thymeleaf、HTML)给用户,不处理业务逻辑。

  • Controller(控制器)
    调度中心,用来接收用户的请求,整个流程的控制器,用来进行数据校验等。

协作流程
用户请求 → Controller → 调用Service → 访问DAO → 返回数据 → 渲染视图。

二、SpringMVC入门案例

2.1 概述

2.1.1 SpringMVC的概述

  • 轻量级Web框架:基于Spring生态,无缝整合IoC、AOP等特性。

  • 请求驱动:围绕DispatcherServlet设计,处理HTTP请求生命周期。

  • 对比Struts2:配置更简洁,性能更高,注解驱动开发更便捷。

2.1.2 SpringMVC在三层架构中的位置

  • ​Spring MVC 属于表示层​​,负责请求调度和视图渲染。

  • ​Service 和 DAO 层属于业务/数据访问层​​,由 Spring 管理,与 MVC 模块解耦。

2.1.3 SpringMVC和Struts2框架的对比

​对比维度​​Spring MVC​​Struts2​
​框架定位​基于 Spring 生态的模块化 MVC 框架,与 Spring 无缝集成。独立的 MVC 框架,脱胎于 Struts1,强调拦截器机制和灵活配置。
​架构模式​前端控制器模式,DispatcherServlet 分发请求到 @Controller前端控制器 + 拦截器链,通过 FilterDispatcher 或 StrutsPrepareAndExecuteFilter 处理请求。
​配置方式​主流使用注解(如 @Controller@RequestMapping),支持 Java 配置类或 XML。早期依赖 XML 配置(struts.xml),注解支持有限,灵活性较低。
​依赖注入​原生支持 Spring 的 IoC/AOP,依赖注入便捷。不依赖 Spring,需手动实现或借助第三方插件。
​性能​性能优化手段丰富(如异步处理、缓存),整体高效。拦截器链较长可能导致性能损耗,优化空间较小。
​安全性​安全实践严格,漏洞较少,社区持续维护。历史漏洞较多(如 CVE-2017-5638),近年活跃度下降,安全性争议较大。
​模板引擎​支持多种视图技术(JSP、Thymeleaf、Freemarker 等)。默认使用 JSP + OGNL 表达式,视图层灵活性一般。
​测试支持​依赖注入和模块化设计,单元测试和集成测试便捷(如 MockMvc)。测试需模拟复杂环境,对单元测试支持较弱。
​学习曲线​功能丰富,需掌握 Spring 生态,学习曲线较陡。概念相对简单,适合传统 MVC 开发者快速上手。
​RESTful 支持​原生支持(@RestController@ResponseBody),集成度高。需借助插件(如 REST 插件),配置复杂。
​社区与生态​社区活跃,文档丰富,与 Spring 生态深度整合(如 Spring Boot)。社区活跃度低,更新缓慢,插件生态逐渐萎缩。
​典型应用场景​企业级复杂应用,微服务架构,需高度定制和扩展的场景。传统中小型项目,对快速开发有需求但技术栈较旧的团队。

​总结:如何选择?​

  1. ​选 Spring MVC​​:

    • 需要企业级功能(如事务管理、安全框架 Spring Security)。

    • 已使用 Spring 生态(如 Spring Boot)或计划构建微服务。

    • 注重性能、可维护性和长期演进。

  2. ​选 Struts2​​:

    • 维护遗留系统且无法迁移。

    • 项目需求简单,无需复杂扩展。

    • 团队熟悉传统 Struts 风格开发。

⚠️ ​​注意​​:Struts2 因安全问题已逐渐被淘汰,新项目强烈建议优先选择 Spring MVC 或其他现代框架(如 Spring Boot + Spring Web)。

2.2 SpringMVC的入门程序

步骤1: 打开IDEA,创建mavenJavaWeb项目

步骤2:项目依赖(pom.xml),引入开发的jar包

    <!-- 版本锁定 --><properties><spring.version>5.0.2.RELEASE</spring.version></properties><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version><scope>test</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency></dependencies>

步骤3:编写index.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>入门程序</title>
</head>
<body>
​
<%--超链接--%>
​
<h3>入门</h3>
​
<a href="/hello.do" >入门程序</a>
​
</body>
</html>

步骤4:编写suc.jsp页面,路径为:/WEB-INF/pages/suc.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>成功</title>
</head>
<body><h3>入门成功了2...</h3>
</body>
</html>

步骤5:编写Controller类和方法

package com.qcby.Controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/*控制器类,处理用户的请求*/
// 把当前类交给IOC容器进行管理
@Controller
public class HelloController {/*** 处理超链接发送出来的请求* @return*/// 配置映射的配置@RequestMapping(path = "/hello.do")public String sayHello(){System.out.println("入门方法执行了2...");// 跳转的JSP页面的路径,默认使用的是请求的转发// return "/WEB-INF/pages/suc.jsp";// 配置了视图解析器后,写法return "suc";}
}

步骤6:配置核心的控制器(配置DispatcherServlet),在web.xml中进行配置

    <!--配置前端控制器--><servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--加载springmvc.xml配置文件,配置的是Spring配置--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:springmvc.xml</param-value></init-param><!--配置启动加载--><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping>

步骤7: 编写/src/main/resources/springmvc.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- 配置spring创建容器时要扫描的包 --><context:component-scan base-package="com.qcby"></context:component-scan><!-- 配置视图解析器 --><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/pages/"></property><property name="suffix" value=".jsp"></property></bean><!-- 配置spring开启注解mvc的支持 --><!--<mvc:annotation-driven></mvc:annotation-driven>-->
</beans>

步骤8:启动Tomcat服务器,进行测试

执行流程:

1. 当启动Tomcat服务器的时候,因为配置了load-on-startup标签,所以会创建DispatcherServlet对象,就会加载springmvc.xml配置文件;

2. 开启了注解扫描,那么HelloController对象就会被创建;

3. 从index.jsp发送请求,请求会先到达DispatcherServlet核心控制器,根据配置@RequestMapping注解找到执行的具体方法;

4. 根据执行方法的返回值,再根据配置的视图解析器,去指定的目录下查找指定名称的JSP文件;

5. Tomcat服务器渲染页面,做出响应。

2.3 执行流程解析

2.3.1 执行流程

1. DispatcherServlet接收请求

作为统一入口,拦截匹配的URL请求。

2. HandlerMapping路由映射

根据@RequestMapping查找对应的Controller方法。

3. HandlerAdapter执行方法

反射调用目标方法,处理业务逻辑。

4. 视图解析与渲染

ViewResolver解析逻辑视图名,渲染JSP/HTML返回客户端。

2.3.2 组件分析

  • 前端控制器(DispatcherServlet)
  • 处理器映射器(HandlerMapping)
  • 处理器(Handler)
  • 处理器适配器(HandlAdapter)
  • 视图解析器(View Resolver)
  • 视图(View)

2.4 RequestMapping注解

1. RequestMapping注解的作用是建立请求URL和处理方法之间的对应关系

2. RequestMapping注解可以作用在方法和类上

  • 作用在类上:第一级的访问目录
  • 作用在方法上:第二级的访问目录
  • 细节:路径可以不编写 / 表示应用的根目录开始

3. RequestMapping的属性

  • path 指定请求路径的url
  • value value属性和path属性是一样的
  • mthod 指定该方法的请求方式(get查 post增 delete删 put改)
  • params 指定限制请求参数的条件
package com.qcby.Controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/*** 7* 角色模块的类*/
@Controller
@RequestMapping(path = "/role")  //一级请求路径
public class RoleController {/*** /role/save.do* method="当前方法允许请求方式能访问"* params="请求路径上传参数"* @return*/@RequestMapping(path = "/save.do",method = {RequestMethod.GET},params = "username")public String save(){System.out.println("保存角色...");return "suc";}@RequestMapping(value = "/delete.do")public String delete(){System.out.println("删除角色...");return "suc";}
}

三、请求参数的绑定

3.1 请求参数的绑定说明

3.1.1 绑定机制

  • 表单提交的数据都是k=v格式的 username=haha&password=123

  • SpringMVC的参数绑定过程是把表单提交的请求参数,作为控制器中方法的参数进行绑定的

  • 要求:提交表单的name和参数的名称是相同的

3.1.2 支持的数据类型

  • 基本数据类型和字符串类型

  • 实体类型(JavaBean)

  • 集合数据类型(List、map集合等)

3.1.3 基本数据类型和字符串类型

  • 提交表单的name和参数的名称是相同的

  • 区分大小写

3.1.4 实体类型(JavaBean)

  • 提交表单的name和JavaBean中的属性名称需要一致

  • 如果一个JavaBean类中包含其他的引用类型,那么表单的name属性需要编写成:对象.属性 例如:address.name

3.1.5 给集合属性数据封装

  • JSP页面编写方式:list[0].属性

3.2 示例

1. /src/main/webapp/demo2/demo2.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head><title>请求参数绑定</title>
</head>
<body>
​
<h3>请求参数绑定入门</h3>
​
<form action="/user/save1.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/><input type="submit" value="提交" />
</form>
​
​
<h3>请求参数绑定(封装到实体类)</h3>
​
<form action="/user/save2.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/>生日:<input type="text" name="birthday" /><br/><input type="submit" value="提交" />
</form>
​
<h3>请求参数绑定(封装到实体类)</h3>
​
<form action="/user/save3.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/>金额:<input type="text" name="address.money" /><br/><input type="submit" value="提交" />
</form>
​
<h3>请求参数绑定(封装到实体类,存在list集合)</h3>
​
<form action="/user/save4.do" method="post">姓名:<input type="text" name="username" /><br/>年龄:<input type="text" name="age" /><br/>金额:<input type="text" name="address.money" /><br/>​集合:<input type="text" name="list[0].money" /><br/>集合:<input type="text" name="list[1].money" /><br/><input type="submit" value="提交" />
</form><h3>请求参数绑定(存储到Map集合)</h3>
<form action="/user/saveMap.do" method="post">姓名:<input type="text" name="map['key1']" /><br/>年龄:<input type="text" name="map['value1']" /><br/><input type="submit" value="提交Map" />
</form>
​
</body>
</html>

2. Javabean代码

package com.qcby.demo2;import org.springframework.format.annotation.DateTimeFormat;import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Map;public class User implements Serializable {private String username;private Integer age;// 生日// 2000-11-11 格式的日期不能进行转换了,开发使用还是比较多,比较简单//@DateTimeFormat(pattern = "yyyy-MM-dd")private Date birthday;// 引用对象private Address address;// list集合private List<Address> list;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public List<Address> getList() {return list;}public void setList(List<Address> list) {this.list = list;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "User{" +"username='" + username + '\'' +", age=" + age +", birthday=" + birthday +", address=" + address +", list=" + list +'}';}
}
package com.qcby.demo2;import java.io.Serializable;public class Address implements Serializable{// 金额private Double money;public Double getMoney() {return money;}public void setMoney(Double money) {this.money = money;}@Overridepublic String toString() {return "Address{" +"money=" + money +'}';}
}

3. controller

package com.qcby.demo2;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Map;/*
用户的模板*/
@Controller
@RequestMapping("/user")
public class UserController {/*** 请求参数的绑定* @return*/@RequestMapping("/save1.do")public String save(String username,Integer age){System.out.println("姓名:"+username);System.out.println("年龄:"+age);return "suc";}/*** 请求参数的绑定* @return*/@RequestMapping("/save2.do")public String save2(User user){System.out.println("user对象:"+user);return "suc";}/*** 请求参数的绑定* @return*/@RequestMapping("/save3.do")public String save3(User user){System.out.println("user对象:"+user);return "suc";}/*** 请求参数的绑定* @return*/@RequestMapping("/save4.do")public String save4(User user){System.out.println("user对象:"+user);return "suc";}/*** 原生的API* @return*/@RequestMapping("/save6.do")public String save6(HttpServletRequest request, HttpServletResponse response){System.out.println(request);// 获取到HttpSession对象HttpSession session = request.getSession();System.out.println(session);System.out.println(response);return "suc";}/*** 接收Map类型参数*/@RequestMapping("/saveMap.do")public String saveMap(@RequestParam Map<String, Object> map) {System.out.println("===== Map集合参数 =====");for (Map.Entry<String, Object> entry : map.entrySet()) {System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());}return "suc"; // 跳转到成功页面}}

在进行中文乱码和日期转换器的配置后,运行tomcat进行测试。

3.3 中文乱码解决

在web.xml中配置CharacterEncodingFilter

    <!-- 配置过滤器,解决中文乱码的问题 --><filter><filter-name>characterEncodingFilter</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></filter><filter-mapping><filter-name>characterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping>

3.4 自定义类型转换器(日期)

3.4.1 使用DateTimeFormat注解

在User.java中添加注解,并在springmvc.xml中配置开启注解。

    // 生日// 2000-11-11 格式的日期不能进行转换了,开发使用还是比较多,比较简单@DateTimeFormat(pattern = "yyyy-MM-dd")
    <!-- 配置spring开启注解mvc的支持 --><mvc:annotation-driven></mvc:annotation-driven>

3.4.2 自定义类型转换器(实现Converter的接口)

package com.qcby.demo2;import org.springframework.core.convert.converter.Converter;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;public class StringToDate implements Converter<String,Date>{public Date convert(String s) {System.out.println("正在转换日期:" + s);// 判断if(s == null){throw new RuntimeException("请输入内容");}// 进行转换//SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//        try {
//            // 进行转换
//            return sdf.parse(s);
//        } catch (ParseException e) {
//            throw new RuntimeException(e);
//        }SimpleDateFormat[] formats = {new SimpleDateFormat("yyyy-MM-dd"),new SimpleDateFormat("yyyy/MM/dd")};for (SimpleDateFormat sdf : formats) {try {return sdf.parse(s);} catch (ParseException ignored) {}}throw new RuntimeException("日期格式错误,支持格式:yyyy-MM-dd 或 yyyy/MM/dd");}
}

注册自定义类型转换器,在springmvc.xml配置文件中编写配置。

    <!--配置日期类型转换器,类型转换器的组件,把日期类型转换注入到组件对象中--><bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><set><bean class="com.qcby.demo2.StringToDate" /></set></property></bean><!--让映射器、适配器和处理器生效(默认不配置也是可以的)--><mvc:annotation-driven conversion-service="conversionService"/>

四、总结与扩展

SpringMVC通过清晰的层次划分和丰富的注解,极大简化了Web开发。建议进一步探索:

  • 文件上传MultipartFile处理文件。

  • 全局异常处理@ControllerAdvice统一异常管理。

  • 拦截器:实现权限校验、日志记录。

通过深入理解核心组件和注解,能够高效构建灵活、可维护的Web应用。

相关文章:

  • Linux中的31个普通信号
  • Redis03-基础-C#客户端
  • Javase 基础入门 —— 06 final + 单例
  • 数据库MySQL学习——day6(多表查询(JOIN)基础)
  • uni-app 中使用 mqtt.js 的完整版
  • 关于百度模型迭代个人见解:技术竞速下的应用价值守恒定律
  • Maven 使用教程
  • 图像生成新势力:GPT-Image-1 与 GPT-4o 在智创聚合 API 的较量
  • 码蹄杯——tips
  • 龙芯远程方案
  • 常用的多传感器数据融合方法
  • 衡石科技:HENGSHI SENSE 数据权限解决方案
  • 从线性回归到逻辑回归
  • Spring XML 外部实体(XXE)指南:示例和预防
  • 使用XMLSpy校验xml是否合法
  • 强化学习中关键超参数的详细说明
  • vue2 开发一个实习管理系统电脑端-前端静态网站练习
  • 基于知识库的客户服务工具
  • Kubernetes学习笔记-环境变量的使用
  • 使用 Vue 3 开发桌面端应用的框架性能对比
  • 伊朗港口爆炸已致46人死亡
  • 葛兰西:“生活就是抵抗”
  • 摩根士丹利基金雷志勇:AI带来的产业演进仍在继续,看好三大景气领域
  • 政治局会议:优化存量商品房收购政策,持续巩固房地产市场稳定态势
  • 复旦大学校长金力:将配套出台多项政策推动科技成果转化
  • 上海车展迎来超百款首发新车,全市多区开展汽车促消费活动