1、学习方法说明
一、SpringMVC 学习核心方法论
SpringMVC 是 Spring 生态的 Web 层框架,学习需遵循「原理先行、实战落地、循序渐进」的原则,核心方法如下:
✅ 先懂原理,再写代码
- 先吃透 MVC 架构、Servlet 基础、SpringMVC 执行流程,再动手写代码,避免只会复制粘贴。
- 重点理解「请求 - 响应」的完整链路,每个组件的作用和分工。
✅ 从传统 XML 到注解,再到 SpringBoot
- 先学传统 XML 配置,理解底层原理;再学注解开发,提升效率;最后过渡到 SpringBoot 自动配置,符合技术演进路线。
✅ 结合 SSM 全栈学习
- SpringMVC 是 Web 层,需结合 Spring(业务层)、MyBatis(持久层)一起学习,理解完整的 SSM 架构流转。
✅ 多调试、多踩坑、多总结
- 遇到 404、500 等错误,通过日志定位问题,总结常见坑(如路径配置、参数绑定、乱码问题)。
✅ 源码辅助理解
- 核心组件(如 DispatcherServlet)的源码不用全背,但要理解核心执行流程,知其然更知其所以然。
2、回顾 MVC 架构
一、MVC 核心定义
MVC 是一种软件架构设计模式 ,将应用程序分为 3 个核心层级,实现「关注点分离」,降低耦合度,提升可维护性。
二、MVC 三层核心角色
| 层级 | 全称 | 核心作用 | 对应技术 |
|---|---|---|---|
| Model(模型层) | Model | 封装业务数据和业务逻辑,处理数据的增删改查 | Service、Dao、Entity |
| View(视图层) | View | 负责数据展示,与用户交互,不处理业务逻辑 | JSP、Thymeleaf、Vue |
| Controller(控制层) | Controller | 接收用户请求,调用 Model 处理业务,将结果返回给 View | SpringMVC Controller |
三、MVC 架构执行流程
- 用户发送请求 → Controller 接收请求
- Controller 调用 Model 处理业务逻辑、操作数据
- Model 处理完成后,将结果返回给 Controller
- Controller 将结果传递给 View,渲染页面
- View 将最终页面响应给用户
四、MVC 架构优势
✅ 解耦 :三层职责分离,修改某一层不影响其他层,符合开闭原则✅ 可复用 :Model 可被多个 View 复用,避免代码冗余✅ 可维护性高 :分层清晰,便于团队协作开发和后期维护✅ 适合 Web 开发:完美适配 Web 应用的「请求 - 响应」模型
3、回顾 Servlet
一、Servlet 核心定义
Servlet 是 Java EE 规范的核心组件,是运行在 Web 服务器(如 Tomcat)上的 Java 程序,用于处理 Web 请求、生成动态响应,是 SpringMVC 的底层基础。
二、Servlet 核心生命周期
| 阶段 | 执行时机 | 核心方法 | 作用 |
|---|---|---|---|
| 实例化 | 第一次请求 / 服务器启动时 | 构造方法 |
创建 Servlet 实例 |
| 初始化 | 实例化后,仅执行 1 次 | init() |
初始化资源(如数据库连接) |
| 服务 | 每次请求时,多次执行 | service() |
处理请求,根据请求方法调用 doGet()/doPost() |
| 销毁 | 服务器关闭 / 项目卸载时 | destroy() |
释放资源 |
三、Servlet 核心问题(传统开发痛点)
传统 Servlet 开发存在以下问题,催生了 SpringMVC:
- 代码冗余:每个请求都需要写一个 Servlet,类爆炸问题严重
- 配置繁琐 :需要在
web.xml中配置 Servlet 映射,修改需重启服务器 - 参数处理麻烦:手动获取请求参数、类型转换、乱码处理
- 页面跳转繁琐:手动编写转发 / 重定向代码
- 与业务层耦合:Servlet 中直接调用 Service,耦合度高
四、SpringMVC 与 Servlet 的关系
SpringMVC 是基于 Servlet 的封装框架 ,核心入口 DispatcherServlet 就是一个 Servlet,它统一处理所有请求,再分发到对应的 Controller,解决了传统 Servlet 的所有痛点。
4、初识 SpringMVC
一、SpringMVC 核心定义
SpringMVC 是 Spring 生态的 Web 层框架,是 Spring 对 Servlet 的封装,实现了 MVC 架构,用于处理 Web 请求、响应,是 Java 后端 Web 开发的主流框架。
二、SpringMVC 核心优势
✅ 原生继承 Spring:无缝整合 Spring IOC/AOP/ 事务,无需额外配置
✅ MVC 架构清晰:分层明确,职责分离,开发效率高
✅ 功能强大:支持参数绑定、文件上传、拦截器、异常处理、RESTful 等
✅ 配置灵活:支持 XML / 注解 / JavaConfig 多种配置方式
✅ 生态完善:完美适配 SSM 架构,是 SpringBoot Web 开发的底层基础
三、第一个 SpringMVC 程序(环境搭建)
1. 导入 Maven 依赖
xml
<dependencies>
<!-- SpringMVC 核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.20</version>
</dependency>
<!-- Servlet API(provided,Tomcat 自带) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- JSP API(provided) -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
</dependencies>
2. 配置 web.xml(核心入口)
xml
<?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. 配置 DispatcherServlet(SpringMVC 核心入口) -->
<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>
<!-- 启动时加载,优先级1 -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- 2. 配置 Servlet 映射,拦截所有请求 -->
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 3. 配置乱码过滤器(POST请求乱码) -->
<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>
</web-app>
3. 配置 springmvc-servlet.xml
xml
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1. 开启组件扫描,扫描 Controller -->
<context:component-scan base-package="com.example.controller"/>
<!-- 2. 配置视图解析器(InternalResourceViewResolver) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 前缀:JSP 所在目录 -->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!-- 后缀:JSP 扩展名 -->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
4. 编写 Controller
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
// 标记为 Controller,注册为 Bean
@Controller
public class HelloController {
// 映射请求路径:/hello
@RequestMapping("/hello")
public String hello() {
// 返回视图名,视图解析器会拼接为 /WEB-INF/jsp/hello.jsp
return "hello";
}
}
5. 编写 JSP 视图
在 WEB-INF/jsp/ 下创建 hello.jsp:
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Hello SpringMVC</title>
</head>
<body>
<h1>Hello, SpringMVC!</h1>
</body>
</html>
6. 测试
启动 Tomcat,访问 http://localhost:8080/hello,即可看到页面,第一个 SpringMVC 程序运行成功!
5、SpringMVC 执行原理(面试必考)
一、核心执行流程(完整 11 步)
SpringMVC 的核心是 DispatcherServlet(前端控制器),所有请求都由它统一分发,执行流程如下:
- 用户发送请求 →
DispatcherServlet拦截所有请求,作为入口 DispatcherServlet调用HandlerMapping(处理器映射器)HandlerMapping根据请求路径,找到对应的Handler(Controller)和拦截器,返回HandlerExecutionChainDispatcherServlet调用HandlerAdapter(处理器适配器)HandlerAdapter适配Handler,执行对应的 Controller 方法- Controller 方法执行完成,返回
ModelAndView(模型数据 + 视图名) HandlerAdapter将ModelAndView返回给DispatcherServletDispatcherServlet调用ViewResolver(视图解析器),根据视图名解析出真实视图(如 JSP)ViewResolver返回视图对象给DispatcherServletDispatcherServlet调用视图的render()方法,渲染模型数据到视图- 视图响应给用户,完成请求
二、核心组件详解
| 组件 | 全称 | 核心作用 |
|---|---|---|
| DispatcherServlet | 前端控制器 | 核心入口,统一处理所有请求,分发请求、协调各组件 |
| HandlerMapping | 处理器映射器 | 根据请求路径,找到对应的 Controller |
| HandlerAdapter | 处理器适配器 | 适配 Controller,执行 Controller 方法 |
| Handler | 处理器 | 即 Controller,处理业务逻辑,返回 ModelAndView |
| ViewResolver | 视图解析器 | 根据视图名,解析出真实视图(如 JSP、Thymeleaf) |
| View | 视图 | 渲染模型数据,响应给用户 |
三、执行流程极简图
用户请求 → DispatcherServlet → HandlerMapping → Handler(Controller)
↓
HandlerAdapter → ModelAndView → ViewResolver → View → 用户响应
6、深入 SpringMVC 学习
一、核心知识点深入
1. 请求参数绑定
SpringMVC 自动将请求参数绑定到 Controller 方法的形参,支持多种类型:
- 基本数据类型、字符串
- 实体类(自动封装,属性名与请求参数名一致)
- 数组、集合
@RequestParam:指定参数名,设置必填 / 默认值@PathVariable:RESTful 路径参数绑定
2. 常用注解
@RequestMapping:映射请求路径,支持方法、类@GetMapping/@PostMapping:指定请求方法(GET/POST)@RequestParam:获取请求参数@PathVariable:获取路径参数@RequestHeader:获取请求头@CookieValue:获取 Cookie 值@ModelAttribute:数据回显、预处理
3. 视图与跳转
- 转发 :
return "视图名"(默认转发,地址栏不变) - 重定向 :
return "redirect:/路径"(地址栏变化,两次请求) - 无视图返回 :
@ResponseBody直接返回 JSON 数据(前后端分离)
4. 拦截器(Interceptor)
- 类似 Servlet 过滤器,用于拦截请求,做权限校验、日志、统一处理
- 实现
HandlerInterceptor接口,重写preHandle()/postHandle()/afterCompletion()方法 - 可配置多个拦截器,按顺序执行
5. 异常处理
- 全局异常处理:
@ControllerAdvice+@ExceptionHandler - 统一处理所有 Controller 的异常,返回友好页面 / JSON
6. 文件上传 / 下载
- 支持单文件 / 多文件上传,通过
MultipartFile接收 - 配置文件上传解析器
CommonsMultipartResolver
7、使用注解开发 SpringMVC
一、核心注解(零 XML 开发)
SpringMVC 支持纯注解开发,完全替代 XML 配置,核心注解如下:
| 注解 | 作用 |
|---|---|
@Controller |
标记类为 Controller,注册为 Bean |
@RequestMapping |
映射请求路径,支持类 + 方法 |
@GetMapping/@PostMapping |
映射 GET/POST 请求 |
@ResponseBody |
直接返回 JSON 数据,不跳转视图 |
@RestController |
@Controller + @ResponseBody 组合,用于前后端分离 |
@RequestParam |
获取请求参数,指定参数名 |
@PathVariable |
获取 RESTful 路径参数 |
@ComponentScan |
开启组件扫描,替代 XML 扫描配置 |
@Configuration |
标记为配置类,替代 XML 配置文件 |
@EnableWebMvc |
开启 SpringMVC 注解支持,替代 XML 配置 |
二、纯注解开发示例
1. 配置类(替代 springmvc-servlet.xml)
@Configuration
@ComponentScan("com.example")
@EnableWebMvc // 开启 SpringMVC 注解支持
public class SpringMVCConfig implements WebMvcConfigurer {
// 配置视图解析器
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp/");
resolver.setSuffix(".jsp");
return resolver;
}
// 配置乱码过滤器(替代 web.xml 配置)
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> encodingFilter() {
FilterRegistrationBean<CharacterEncodingFilter> bean = new FilterRegistrationBean<>();
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
bean.setFilter(filter);
bean.addUrlPatterns("/*");
return bean;
}
}
2. 初始化类(替代 web.xml)
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
// 加载 Spring 容器配置(业务层、持久层)
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
// 加载 SpringMVC 配置(Web 层)
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMVCConfig.class};
}
// 配置 DispatcherServlet 映射,拦截所有请求
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
3. Controller 注解开发
@Controller
@RequestMapping("/user") // 类上路径,所有方法的父路径
public class UserController {
// 映射路径:/user/hello,GET 请求
@GetMapping("/hello")
public String hello(Model model) {
// 添加模型数据
model.addAttribute("msg", "Hello, SpringMVC Annotation!");
// 返回视图名
return "hello";
}
// 直接返回 JSON 数据(前后端分离)
@GetMapping("/json")
@ResponseBody
public User json() {
return new User(1, "张三", "123456", "zhangsan@example.com");
}
}
三、注解开发优势
✅ 零 XML 配置:减少配置文件,开发效率高
✅ 代码简洁:直接在类 / 方法上标记注解,可读性高
✅ 类型安全:编译期检查,避免配置错误
✅ 符合现代开发:SpringBoot 主流开发方式,无缝衔接
8、Controller 配置总结
一、Controller 核心配置方式对比
| 配置方式 | 核心特点 | 适用场景 |
|---|---|---|
| XML 配置 | 传统方式,在 XML 中注册 Bean、映射路径 | 传统 SSM 项目、复杂配置 |
| 注解配置 | 纯注解,@Controller+@RequestMapping |
现代项目、SpringBoot、前后端分离 |
| JavaConfig 配置 | 纯 Java 配置类,完全替代 XML | 纯注解项目、SpringBoot |
二、Controller 核心配置要点
1. 路径映射
- 类上
@RequestMapping("/user"):所有方法的父路径 - 方法上
@RequestMapping("/hello"):子路径,最终路径/user/hello @GetMapping/@PostMapping:指定请求方法,避免 GET/POST 混淆- 通配符:
@RequestMapping("/user/*")匹配/user/下所有路径
2. 参数绑定
- 自动绑定:请求参数名与形参名一致,自动赋值
@RequestParam:指定参数名,设置required = false(非必填)、defaultValue(默认值)- 实体类绑定:请求参数名与实体类属性一致,自动封装
@PathVariable:RESTful 路径参数,如/user/{id}
3. 数据传递
Model/ModelMap:向视图传递模型数据ModelAndView:同时传递模型数据和视图名(传统方式)@SessionAttribute:将数据存入 Session@CookieValue:获取 Cookie 数据
4. 视图跳转
- 转发:
return "视图名"(默认,地址栏不变) - 重定向:
return "redirect:/路径"(地址栏变化,两次请求) - 无视图:
@ResponseBody直接返回 JSON(前后端分离)
5. 异常处理
- 局部异常:
@ExceptionHandler标注在 Controller 内,处理当前 Controller 异常 - 全局异常:
@ControllerAdvice+@ExceptionHandler,处理所有 Controller 异常
三、Controller 开发最佳实践
✅ RESTful 风格 :使用 @GetMapping/@PostMapping/@PutMapping/@DeleteMapping 设计接口
✅ 参数校验 :使用 @Valid + JSR-303 注解,校验请求参数
✅ 统一返回格式 :封装统一的返回结果类(如 Result),@ResponseBody 返回 JSON
✅ 统一异常处理 :使用 @ControllerAdvice 做全局异常处理,避免代码冗余
✅ 拦截器统一处理:使用拦截器做权限校验、日志、统一处理,解耦 Controller
9、RequestMapping 说明
一、核心定义
@RequestMapping是 SpringMVC 最核心的注解之一,用于将 HTTP 请求映射到 Controller 的处理方法 ,可标注在类 或方法上,是请求入口的核心配置。
二、核心属性详解
| 属性 | 作用 | 示例 |
|---|---|---|
value/path |
指定请求路径(别名,二选一) | @RequestMapping("/user") |
method |
指定请求方法(GET/POST/PUT/DELETE 等) | method = RequestMethod.GET |
params |
指定请求参数条件,满足才映射 | params = "id"(必须有 id 参数) |
headers |
指定请求头条件,满足才映射 | headers = "Content-Type=application/json" |
consumes |
指定请求的 Content-Type | consumes = "application/json" |
produces |
指定响应的 Content-Type | produces = "application/json;charset=utf-8" |
三、使用示例
1. 类 + 方法组合映射
@Controller
@RequestMapping("/user") // 类上路径:所有方法的父路径
public class UserController {
// 最终路径:/user/hello,支持GET/POST
@RequestMapping("/hello")
public String hello() {
return "hello";
}
// 最终路径:/user/get,仅支持GET请求
@RequestMapping(value = "/get", method = RequestMethod.GET)
public String get() {
return "get";
}
}
2. 简化请求方法注解(Spring 4.3+)
Spring 提供了@GetMapping/@PostMapping等衍生注解,替代method属性,更简洁:
@Controller
@RequestMapping("/user")
public class UserController {
// 等价于 @RequestMapping(value = "/get", method = RequestMethod.GET)
@GetMapping("/get")
public String get() {
return "get";
}
// 等价于 @RequestMapping(value = "/add", method = RequestMethod.POST)
@PostMapping("/add")
public String add() {
return "add";
}
}
四、路径通配符
?:匹配单个字符,如/user/?匹配/user/a、/user/1*:匹配任意多个字符(不包含多级路径),如/user/*匹配/user/abc**:匹配多级路径,如/user/**匹配/user/abc/def
10、RestFul 风格讲解
一、RESTful 核心定义
REST(Representational State Transfer,表述性状态转移)是一种软件架构风格 ,用于设计网络应用的 API,核心是用 URL 定位资源,用 HTTP 方法描述操作,是前后端分离项目的主流 API 设计规范。
二、RESTful 核心设计规范
| HTTP 方法 | 操作 | 传统 URL | RESTful URL | 说明 |
|---|---|---|---|---|
GET |
查询 | /user/getUserById?id=1 |
/user/1 |
查询 ID 为 1 的用户 |
POST |
新增 | /user/addUser |
/user |
新增用户 |
PUT |
修改 | /user/updateUser |
/user/1 |
修改 ID 为 1 的用户 |
DELETE |
删除 | /user/deleteUser?id=1 |
/user/1 |
删除 ID 为 1 的用户 |
三、SpringMVC 中 RESTful 实现
1. 核心注解@PathVariable
用于获取 RESTful 路径中的参数,绑定到方法形参:
@RestController
@RequestMapping("/user")
public class UserController {
// GET /user/1 → 查询ID为1的用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Integer id) {
return userService.getUserById(id);
}
// POST /user → 新增用户
@PostMapping
public User addUser(@RequestBody User user) {
userService.addUser(user);
return user;
}
// PUT /user/1 → 修改ID为1的用户
@PutMapping("/{id}")
public User updateUser(@PathVariable Integer id, @RequestBody User user) {
user.setId(id);
userService.updateUser(user);
return user;
}
// DELETE /user/1 → 删除ID为1的用户
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Integer id) {
userService.deleteUser(id);
}
}
四、RESTful 优势
✅ URL 简洁:用路径代替参数,可读性高
✅ 语义清晰:HTTP 方法对应操作,见名知意
✅ 无状态:每个请求独立,适合分布式、微服务
✅ 前后端分离友好:统一 API 规范,便于前端调用
11、重定向和转发
一、核心定义与区别
转发(Forward)和重定向(Redirect)是 Web 开发中两种页面跳转方式,核心区别如下:
| 特性 | 转发(Forward) | 重定向(Redirect) |
|---|---|---|
| 请求次数 | 1 次(服务器内部跳转) | 2 次(浏览器发起新请求) |
| 地址栏变化 | 不变 | 变为新的 URL |
| 数据共享 | 共享 request 域数据 | 不共享 request 域数据 |
| 跳转范围 | 仅当前项目内资源 | 可跳转到任意外部资源 |
| 底层实现 | 服务器内部RequestDispatcher.forward() |
浏览器HttpServletResponse.sendRedirect() |
| SpringMVC 写法 | return "视图名"(默认) |
return "redirect:/路径" |
二、SpringMVC 中实现
1. 转发(默认)
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/forward")
public String forward(Model model) {
model.addAttribute("msg", "转发测试");
// 转发到/hello路径,地址栏不变,共享Model数据
return "hello";
}
}
2. 重定向
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/redirect")
public String redirect() {
// 重定向到/hello路径,地址栏变为/hello,发起新请求
return "redirect:/hello";
}
}
三、使用场景
- 转发:需要共享 request 数据、跳转到项目内页面、避免重复请求
- 重定向:避免表单重复提交、跳转到外部链接、刷新页面不重复提交
12、接收请求参数及数据回显
一、接收请求参数的方式
SpringMVC 支持多种参数绑定方式,自动将请求参数绑定到方法形参:
1. 基本数据类型 / 字符串
请求参数名与形参名一致,自动绑定:
@GetMapping("/get")
public String get(String name, Integer age) {
// 自动绑定请求参数:?name=张三&age=18
System.out.println(name + "," + age);
return "hello";
}
-
若参数名不一致,用
@RequestParam指定:@GetMapping("/get")
public String get(@RequestParam("username") String name) {
// 绑定请求参数?username=张三到name形参
return "hello";
}
2. 实体类绑定
请求参数名与实体类属性一致,自动封装到实体类:
@PostMapping("/add")
public String add(User user) {
// 自动封装请求参数:?name=张三&age=18&email=xxx@xx.com
System.out.println(user);
return "hello";
}
3. 数组 / 集合绑定
@GetMapping("/batch")
public String batch(String[] ids) {
// 绑定请求参数:?ids=1&ids=2&ids=3
return "hello";
}
4. @PathVariable(RESTful 路径参数)
@GetMapping("/{id}")
public String get(@PathVariable Integer id) {
// 绑定路径参数:/user/1 → id=1
return "hello";
}
5. @RequestBody(JSON 参数)
用于接收 POST 请求的 JSON 格式参数,前后端分离常用:
@PostMapping("/add")
public String add(@RequestBody User user) {
// 接收JSON格式的请求体,自动封装到User
return "hello";
}
二、数据回显(向视图传递数据)
SpringMVC 提供多种方式向视图传递数据,渲染页面:
1. Model/ModelMap(最常用)
@GetMapping("/hello")
public String hello(Model model) {
// 向request域添加数据,视图可通过${msg}获取
model.addAttribute("msg", "Hello SpringMVC");
model.addAttribute("user", new User(1, "张三"));
return "hello";
}
2. ModelAndView
@GetMapping("/hello")
public ModelAndView hello() {
ModelAndView mv = new ModelAndView();
// 设置视图名
mv.setViewName("hello");
// 添加数据
mv.addObject("msg", "Hello SpringMVC");
return mv;
}
3. @SessionAttribute
将数据存入 Session 域,跨请求共享:
@GetMapping("/session")
public String session(@SessionAttribute("user") User user) {
// 从Session获取user数据
return "hello";
}
13、乱码问题解决
一、常见乱码场景
- POST 请求参数乱码:POST 请求的中文参数乱码
- GET 请求参数乱码:GET 请求的中文参数乱码(Tomcat 版本差异)
- 响应乱码:返回的 JSON / 页面中文乱码
二、解决方案
1. POST 请求乱码(最常见)
配置 Spring 提供的CharacterEncodingFilter,在web.xml中添加:
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>
-
纯注解开发:在配置类中注册 Filter:
@Bean
public FilterRegistrationBean<CharacterEncodingFilter> encodingFilter() {
FilterRegistrationBean<CharacterEncodingFilter> bean = new FilterRegistrationBean<>();
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
filter.setForceEncoding(true);
bean.setFilter(filter);
bean.addUrlPatterns("/*");
return bean;
}
2. GET 请求乱码(Tomcat 8 以下)
Tomcat 8 + 已默认 UTF-8,Tomcat 7 及以下需修改conf/server.xml,在 Connector 标签添加URIEncoding="UTF-8":
xml
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"/>
3. 响应 JSON 乱码
在@RequestMapping中指定produces,或配置消息转换器:
@GetMapping(value = "/json", produces = "application/json;charset=utf-8")
@ResponseBody
public User json() {
return new User(1, "张三");
}
-
全局配置:在 SpringMVC 配置中统一消息转换器:
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setDefaultCharset(StandardCharsets.UTF_8);
converters.add(converter);
}
}
14、什么是 JSON
一、JSON 核心定义
JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种轻量级数据交换格式,基于 JavaScript 语法,独立于编程语言,是前后端分离、接口交互的主流数据格式。
二、JSON 语法规则
- 数据以键值对形式存在 :
"key": value - 键必须用双引号,值可以是字符串、数字、布尔、数组、对象、null
- 数据用逗号分隔,最后一个键值对无逗号
- 对象用
{}包裹 ,数组用[]包裹
三、JSON 示例
json
{
"id": 1,
"name": "张三",
"age": 18,
"email": "zhangsan@example.com",
"hobbies": ["篮球", "音乐"],
"address": {
"city": "北京",
"street": "中关村"
}
}
四、JSON 优势
✅ 轻量简洁:格式简单,易于阅读和编写
✅ 跨语言:几乎所有编程语言都支持 JSON 解析
✅ 前后端分离友好:完美适配 AJAX 请求,是 RESTful API 的标准数据格式
✅ 易于解析:解析速度快,性能高
15、Jackson 使用
一、Jackson 核心定义
Jackson 是 SpringMVC 默认集成的JSON 处理库 ,用于 Java 对象与 JSON 的互相转换,是 SpringMVC@ResponseBody的底层实现,无需额外配置即可使用。
二、核心依赖
xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
- SpringMVC 已默认集成,无需手动导入(spring-webmvc 依赖中包含)
三、核心 API(ObjectMapper)
ObjectMapper是 Jackson 的核心类,用于对象与 JSON 的转换:
ObjectMapper mapper = new ObjectMapper();
// 1. Java对象 → JSON字符串
User user = new User(1, "张三", 18);
String json = mapper.writeValueAsString(user);
// 2. JSON字符串 → Java对象
User user = mapper.readValue(json, User.class);
// 3. Java对象 → JSON文件
mapper.writeValue(new File("user.json"), user);
// 4. JSON文件 → Java对象
User user = mapper.readValue(new File("user.json"), User.class);
四、SpringMVC 中使用(@ResponseBody)
SpringMVC 自动集成 Jackson,@ResponseBody注解会自动将返回值转换为 JSON:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/json")
public User json() {
// 自动将User对象转换为JSON,响应给前端
return new User(1, "张三", 18, "zhangsan@example.com");
}
}
五、常用注解
| 注解 | 作用 |
|---|---|
@JsonProperty |
指定 JSON 字段名,解决属性名与字段名不一致 |
@JsonIgnore |
忽略该属性,不参与 JSON 序列化 |
@JsonFormat |
指定日期格式,如@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
@JsonNaming |
指定命名策略,如驼峰转下划线 |
16、Fastjson 使用
一、Fastjson 核心定义
Fastjson 是阿里巴巴开源的高性能 JSON 处理库 ,用于 Java 对象与 JSON 的互相转换,以极快的解析速度著称,是国内常用的 JSON 库。
二、核心依赖
xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
三、核心 API(JSON 类)
JSON是 Fastjson 的核心工具类,提供静态方法实现转换:
// 1. Java对象 → JSON字符串
User user = new User(1, "张三", 18);
String json = JSON.toJSONString(user);
// 2. JSON字符串 → Java对象
User user = JSON.parseObject(json, User.class);
// 3. JSON数组 → List集合
String jsonArray = "[{\"id\":1,\"name\":\"张三\"},{\"id\":2,\"name\":\"李四\"}]";
List<User> list = JSON.parseArray(jsonArray, User.class);
// 4. List集合 → JSON数组
String jsonArray = JSON.toJSONString(list);
四、SpringMVC 中集成 Fastjson
替换默认的 Jackson,使用 Fastjson 作为消息转换器:
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 创建Fastjson消息转换器
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
// 配置序列化特性
FastJsonConfig config = new FastJsonConfig();
config.setCharset(StandardCharsets.UTF_8);
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
converter.setFastJsonConfig(config);
// 添加到转换器列表
converters.add(converter);
}
}
五、Fastjson vs Jackson 对比
| 特性 | Fastjson | Jackson |
|---|---|---|
| 性能 | 极快,解析速度领先 | 快,稳定 |
| Spring 集成 | 需手动配置 | 默认集成,零配置 |
| 社区维护 | 曾有安全漏洞,维护活跃 | 维护稳定,生态完善 |
| 使用难度 | API 简单,上手快 | API 略复杂,功能强大 |
| 适用场景 | 追求极致性能、国内项目 | Spring 生态、企业级项目 |
17、ssm 整合:Mybatis 层
一、MyBatis 层核心目标
将 MyBatis 的核心组件(SqlSessionFactory、Mapper、实体类、Mapper.xml)交给 Spring 容器管理,实现数据源统一管理、Mapper 自动注入、事务统一控制。
二、MyBatis 层核心配置
1. 项目结构(MyBatis 相关)
src/main/java
└── com.example
├── pojo # 实体类
│ └── Book.java
├── mapper # Mapper接口
│ └── BookMapper.java
└── service # Service层(后续Spring层)
src/main/resources
├── mapper # Mapper.xml映射文件
│ └── BookMapper.xml
├── mybatis-config.xml # MyBatis核心配置(可简化)
└── db.properties # 数据库配置
2. 实体类(Book.java)
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Book {
private Integer id;
private String bookName;
private String author;
private Double price;
}
3. Mapper 接口(BookMapper.java)
public interface BookMapper {
// 查询所有书籍
List<Book> queryAllBook();
// 根据ID查询
Book queryBookById(Integer id);
// 添加书籍
int addBook(Book book);
// 修改书籍
int updateBook(Book book);
// 删除书籍
int deleteBook(Integer id);
// 搜索书籍
List<Book> searchBook(String bookName);
}
4. Mapper.xml(BookMapper.xml)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.BookMapper">
<select id="queryAllBook" resultType="Book">
SELECT * FROM books
</select>
<select id="queryBookById" parameterType="int" resultType="Book">
SELECT * FROM books WHERE id = #{id}
</select>
<insert id="addBook" parameterType="Book">
INSERT INTO books (bookName, author, price)
VALUES (#{bookName}, #{author}, #{price})
</insert>
<update id="updateBook" parameterType="Book">
UPDATE books
SET bookName=#{bookName}, author=#{author}, price=#{price}
WHERE id=#{id}
</update>
<delete id="deleteBook" parameterType="int">
DELETE FROM books WHERE id=#{id}
</delete>
<select id="searchBook" parameterType="string" resultType="Book">
SELECT * FROM books WHERE bookName LIKE CONCAT('%', #{bookName}, '%')
</select>
</mapper>
5. MyBatis 核心配置(mybatis-config.xml,可简化)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 开启驼峰命名 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 开启日志 -->
<setting name="logImpl" value="LOG4J"/>
</settings>
<!-- 别名配置,Spring层统一配置,此处可省略 -->
<!-- <typeAliases>
<package name="com.example.pojo"/>
</typeAliases> -->
</configuration>
18、ssm 整合:Spring 层
一、Spring 层核心目标
- 统一管理数据源、
SqlSessionFactory、Mapper 扫描 - 管理 Service 层 Bean,实现依赖注入
- 配置声明式事务,统一控制 MyBatis 事务
二、Spring 层核心配置
1. 数据库配置(db.properties)
properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/ssm_db?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=root
2. Spring 核心配置(applicationContext.xml)
xml
<?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:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 加载数据库配置文件 -->
<context:property-placeholder location="classpath:db.properties"/>
<!-- 2. 配置数据源(Druid) -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 3. 配置SqlSessionFactory(MyBatis核心) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 加载MyBatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 加载Mapper.xml -->
<property name="mapperLocations" value="classpath:mapper/*.xml"/>
<!-- 配置别名 -->
<property name="typeAliasesPackage" value="com.example.pojo"/>
</bean>
<!-- 4. 扫描Mapper接口,自动注册为Bean -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.example.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 5. 扫描Service层 -->
<context:component-scan base-package="com.example.service"/>
<!-- 6. 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 7. 开启声明式事务注解支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
3. Service 层接口与实现
// BookService.java
public interface BookService {
List<Book> queryAllBook();
Book queryBookById(Integer id);
void addBook(Book book);
void updateBook(Book book);
void deleteBook(Integer id);
List<Book> searchBook(String bookName);
}
// BookServiceImpl.java
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookMapper bookMapper;
@Override
public List<Book> queryAllBook() {
return bookMapper.queryAllBook();
}
@Override
public Book queryBookById(Integer id) {
return bookMapper.queryBookById(id);
}
@Override
@Transactional // 开启事务
public void addBook(Book book) {
bookMapper.addBook(book);
}
@Override
@Transactional
public void updateBook(Book book) {
bookMapper.updateBook(book);
}
@Override
@Transactional
public void deleteBook(Integer id) {
bookMapper.deleteBook(id);
}
@Override
public List<Book> searchBook(String bookName) {
return bookMapper.searchBook(bookName);
}
}
19、ssm 整合:SpringMVC 层
一、SpringMVC 层核心目标
- 配置 DispatcherServlet,拦截所有请求
- 扫描 Controller 层,处理 Web 请求
- 配置视图解析器、乱码过滤器,实现页面跳转与数据响应
二、SpringMVC 层核心配置
1. web.xml(核心入口)
xml
<?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. 配置Spring监听器,启动Spring容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 2. 配置乱码过滤器 -->
<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>
<!-- 3. 配置DispatcherServlet(SpringMVC核心入口) -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<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>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
2. SpringMVC 配置(springmvc-servlet.xml)
xml
<?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/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 1. 扫描Controller层 -->
<context:component-scan base-package="com.example.controller"/>
<!-- 2. 开启注解驱动 -->
<mvc:annotation-driven>
<!-- 配置JSON乱码解决 -->
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="defaultCharset" value="UTF-8"/>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 3. 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!-- 4. 静态资源放行 -->
<mvc:default-servlet-handler/>
</beans>
20、ssm 整合:查询书籍功能
一、功能目标
实现查询所有书籍,在页面展示书籍列表,是 SSM 整合的第一个完整流程。
二、Controller 层实现
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 查询所有书籍
@GetMapping("/all")
public String queryAllBook(Model model) {
List<Book> bookList = bookService.queryAllBook();
// 将数据存入Model,传递给视图
model.addAttribute("bookList", bookList);
// 跳转到书籍列表页面
return "bookList";
}
}
三、页面实现(bookList.jsp)
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>书籍列表</title>
</head>
<body>
<h1>书籍列表</h1>
<a href="${pageContext.request.contextPath}/book/toAdd">添加书籍</a>
<table border="1" cellpadding="10" cellspacing="0">
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>价格</th>
<th>操作</th>
</tr>
<c:forEach items="${bookList}" var="book">
<tr>
<td>${book.id}</td>
<td>${book.bookName}</td>
<td>${book.author}</td>
<td>${book.price}</td>
<td>
<a href="${pageContext.request.contextPath}/book/toUpdate?id=${book.id}">修改</a>
<a href="${pageContext.request.contextPath}/book/delete/${book.id}">删除</a>
</td>
</tr>
</c:forEach>
</table>
</body>
</html>
四、测试
启动 Tomcat,访问 http://localhost:8080/book/all,即可看到书籍列表,查询功能完成。
21、ssm 整合:添加书籍功能
一、功能目标
实现添加书籍,包含跳转到添加页面、提交表单、保存到数据库、跳转回列表页。
二、Controller 层实现
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 跳转到添加页面
@GetMapping("/toAdd")
public String toAdd() {
return "addBook";
}
// 提交添加表单
@PostMapping("/add")
public String addBook(Book book) {
bookService.addBook(book);
// 重定向到列表页,避免表单重复提交
return "redirect:/book/all";
}
}
三、页面实现(addBook.jsp)
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加书籍</title>
</head>
<body>
<h1>添加书籍</h1>
<form action="${pageContext.request.contextPath}/book/add" method="post">
书名:<input type="text" name="bookName"><br>
作者:<input type="text" name="author"><br>
价格:<input type="text" name="price"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
22、ssm 整合:修改删除书籍
一、修改书籍功能
1. Controller 层实现
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 跳转到修改页面,根据ID查询书籍
@GetMapping("/toUpdate")
public String toUpdate(Integer id, Model model) {
Book book = bookService.queryBookById(id);
model.addAttribute("book", book);
return "updateBook";
}
// 提交修改表单
@PostMapping("/update")
public String updateBook(Book book) {
bookService.updateBook(book);
return "redirect:/book/all";
}
}
2. 页面实现(updateBook.jsp)
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>修改书籍</title>
</head>
<body>
<h1>修改书籍</h1>
<form action="${pageContext.request.contextPath}/book/update" method="post">
<input type="hidden" name="id" value="${book.id}">
书名:<input type="text" name="bookName" value="${book.bookName}"><br>
作者:<input type="text" name="author" value="${book.author}"><br>
价格:<input type="text" name="price" value="${book.price}"><br>
<input type="submit" value="提交修改">
</form>
</body>
</html>
二、删除书籍功能
1. Controller 层实现
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 删除书籍
@GetMapping("/delete/{id}")
public String deleteBook(@PathVariable Integer id) {
bookService.deleteBook(id);
return "redirect:/book/all";
}
}
23、ssm 整合:新增搜索功能
一、功能目标
实现按书名模糊搜索,在列表页添加搜索框,输入书名后筛选结果。
二、Controller 层实现
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 搜索书籍
@GetMapping("/search")
public String searchBook(String bookName, Model model) {
List<Book> bookList = bookService.searchBook(bookName);
model.addAttribute("bookList", bookList);
return "bookList";
}
}
三、页面改造(bookList.jsp,添加搜索框)
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>书籍列表</title>
</head>
<body>
<h1>书籍列表</h1>
<!-- 搜索框 -->
<form action="${pageContext.request.contextPath}/book/search" method="get">
<input type="text" name="bookName" placeholder="请输入书名">
<input type="submit" value="搜索">
<a href="${pageContext.request.contextPath}/book/all">重置</a>
</form>
<a href="${pageContext.request.contextPath}/book/toAdd">添加书籍</a>
<table border="1" cellpadding="10" cellspacing="0">
<!-- 表格内容同之前 -->
</table>
</body>
</html>
24、Ajax 初体验
一、Ajax 核心定义
AJAX(Asynchronous JavaScript and XML,异步 JavaScript 和 XML)是一种异步交互技术,无需刷新整个页面,即可与服务器进行数据交互,实现页面局部刷新,是前后端分离的核心技术。
二、SpringMVC 中 Ajax 实现(以搜索书籍为例)
1. 引入 jQuery(前端依赖)
html
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
2. Controller 层(返回 JSON)
java
@Controller
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// Ajax搜索,返回JSON
@GetMapping("/ajaxSearch")
@ResponseBody
public List<Book> ajaxSearch(String bookName) {
return bookService.searchBook(bookName);
}
}
3. 前端 Ajax 代码
html
<script>
function searchBook() {
// 获取输入的书名
var bookName = $("#searchInput").val();
// 发送Ajax请求
$.ajax({
url: "${pageContext.request.contextPath}/book/ajaxSearch",
type: "GET",
data: {bookName: bookName},
dataType: "json",
success: function (data) {
// 清空表格
$("#bookTable").empty();
// 拼接表格行
var html = "";
for (var i = 0; i < data.length; i++) {
var book = data[i];
html += "<tr>";
html += "<td>" + book.id + "</td>";
html += "<td>" + book.bookName + "</td>";
html += "<td>" + book.author + "</td>";
html += "<td>" + book.price + "</td>";
html += "</tr>";
}
// 将HTML插入表格
$("#bookTable").html(html);
}
});
}
</script>
<!-- 搜索框 -->
<input type="text" id="searchInput" placeholder="请输入书名">
<button onclick="searchBook()">搜索</button>
<!-- 表格 -->
<table border="1" cellpadding="10" cellspacing="0">
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>价格</th>
</tr>
</thead>
<tbody id="bookTable">
<!-- 动态加载数据 -->
</tbody>
</table>
三、Ajax 核心优势
✅ 异步交互:无需刷新页面,提升用户体验
✅ 局部刷新:仅更新需要变化的部分,减少网络传输
✅ 前后端分离:前端负责页面渲染,后端负责接口,分工明确
✅ 高性能:减少服务器压力,提升响应速度
25、Ajax 异步加载数据
一、核心定义
Ajax(Asynchronous JavaScript and XML)的核心是异步交互:在不刷新整个页面的前提下,与服务器进行数据通信,实现页面局部数据的动态加载,大幅提升用户体验,是前后端分离的核心技术。
二、异步加载完整示例(书籍列表)
1. Controller 层(返回 JSON 数据)
@RestController
@RequestMapping("/book")
public class BookController {
@Autowired
private BookService bookService;
// 异步加载所有书籍,返回JSON
@GetMapping("/ajax/list")
public List<Book> ajaxLoadBookList() {
return bookService.queryAllBook();
}
}
2. 前端页面(jQuery 异步加载)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Ajax异步加载书籍列表</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body>
<h1>书籍列表(异步加载)</h1>
<button id="loadBtn">点击加载数据</button>
<table border="1" cellpadding="10" cellspacing="0" id="bookTable">
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>价格</th>
</tr>
</thead>
<tbody>
<!-- 异步加载数据 -->
</tbody>
</table>
<script>
$(function () {
// 点击按钮异步加载数据
$("#loadBtn").click(function () {
$.ajax({
url: "${pageContext.request.contextPath}/book/ajax/list",
type: "GET",
dataType: "json",
success: function (data) {
// 清空表格
var tbody = $("#bookTable tbody");
tbody.empty();
// 遍历数据,拼接表格行
for (var i = 0; i < data.length; i++) {
var book = data[i];
var tr = "<tr>" +
"<td>" + book.id + "</td>" +
"<td>" + book.bookName + "</td>" +
"<td>" + book.author + "</td>" +
"<td>" + book.price + "</td>" +
"</tr>";
tbody.append(tr);
}
},
error: function () {
alert("数据加载失败!");
}
});
});
});
</script>
</body>
</html>
三、异步加载核心要点
✅ 异步特性 :async: true(默认),请求发送后不阻塞页面,响应回来后执行回调
✅ 局部刷新:仅更新表格数据,页面其他部分不变
✅ 前后端解耦:后端只提供 JSON 接口,前端负责页面渲染
✅ 性能优化:减少页面整体刷新,降低服务器压力
26、Ajax 验证用户名体验
一、功能目标
实现注册页用户名实时验证:用户输入用户名后,异步请求服务器校验用户名是否已存在,无需提交表单,提升用户体验。
二、完整实现
1. 实体类与 Mapper(User 相关)
java
@Data
public class User {
private Integer id;
private String username;
private String password;
}
// UserMapper.java
public interface UserMapper {
// 根据用户名查询用户
User queryUserByUsername(String username);
}
2. Service 层
java
public interface UserService {
// 校验用户名是否存在
boolean checkUsername(String username);
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public boolean checkUsername(String username) {
return userMapper.queryUserByUsername(username) == null;
}
}
3. Controller 层
java
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 校验用户名是否可用
@GetMapping("/checkUsername")
public Map<String, Object> checkUsername(String username) {
Map<String, Object> result = new HashMap<>();
boolean isAvailable = userService.checkUsername(username);
result.put("code", isAvailable ? 200 : 500);
result.put("msg", isAvailable ? "用户名可用" : "用户名已存在");
return result;
}
}
4. 前端注册页
html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>注册页</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<style>.error{color:red;}.success{color:green;}</style>
</head>
<body>
<h1>用户注册</h1>
<form action="${pageContext.request.contextPath}/user/register" method="post">
<div>
用户名:<input type="text" name="username" id="username">
<span id="usernameTip"></span>
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<input type="submit" value="注册" id="registerBtn">
</div>
</form>
<script>
$(function () {
// 用户名输入框失去焦点时,异步校验
$("#username").blur(function () {
var username = $(this).val();
if (username == "") {
$("#usernameTip").text("用户名不能为空").addClass("error");
return;
}
// 发送Ajax请求
$.ajax({
url: "${pageContext.request.contextPath}/user/checkUsername",
type: "GET",
data: {username: username},
dataType: "json",
success: function (data) {
if (data.code == 200) {
$("#usernameTip").text(data.msg).removeClass("error").addClass("success");
$("#registerBtn").prop("disabled", false);
} else {
$("#usernameTip").text(data.msg).removeClass("success").addClass("error");
$("#registerBtn").prop("disabled", true);
}
}
});
});
});
</script>
</body>
</html>
27、拦截器是什么
一、核心定义
SpringMVC 拦截器(Interceptor)是 SpringMVC 提供的AOP 增强组件 ,用于拦截 Controller 的请求,在请求处理的前置、后置、完成阶段执行自定义逻辑,类似 Servlet 的 Filter,但更聚焦于 SpringMVC 请求链路。
二、核心方法与执行流程
拦截器需实现HandlerInterceptor接口,核心 3 个方法:
| 方法 | 执行时机 | 作用 |
|---|---|---|
preHandle() |
Controller 方法执行前 | 权限校验、登录判断、日志记录,返回true放行,false拦截 |
postHandle() |
Controller 方法执行后 、视图渲染前 | 修改 Model 数据、统一响应处理 |
afterCompletion() |
视图渲染完成后 | 资源释放、日志记录、异常处理 |
三、自定义拦截器实现(登录拦截)
@Component
public class LoginInterceptor implements HandlerInterceptor {
// 前置拦截:登录校验
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从Session获取用户信息
User user = (User) request.getSession().getAttribute("loginUser");
// 未登录,重定向到登录页
if (user == null) {
response.sendRedirect(request.getContextPath() + "/user/toLogin");
return false;
}
// 已登录,放行
return true;
}
// 后置处理
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 可修改Model数据
}
// 完成后处理
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 资源释放
}
}
四、拦截器配置(SpringMVC 配置)
xml
<!-- springmvc-servlet.xml -->
<mvc:interceptors>
<!-- 配置登录拦截器,拦截所有请求 -->
<mvc:interceptor>
<!-- 拦截所有请求 -->
<mvc:mapping path="/**"/>
<!-- 排除登录相关请求 -->
<mvc:exclude-mapping path="/user/toLogin"/>
<mvc:exclude-mapping path="/user/login"/>
<mvc:exclude-mapping path="/user/checkUsername"/>
<!-- 引用拦截器Bean -->
<ref bean="loginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
五、拦截器 vs 过滤器
| 特性 | 拦截器(Interceptor) | 过滤器(Filter) |
|---|---|---|
| 所属框架 | SpringMVC | Servlet 原生 |
| 拦截范围 | 仅拦截 SpringMVC 请求(Controller) | 拦截所有 Web 请求(包括静态资源) |
| 依赖容器 | 依赖 Spring 容器 | 依赖 Servlet 容器 |
| 执行时机 | DispatcherServlet 之后,Controller 之前 | Servlet 之前,所有请求入口 |
| 适用场景 | 登录校验、权限控制、SpringMVC 请求增强 | 乱码过滤、全局请求处理 |
28、登录判断验证
一、功能目标
结合拦截器实现完整登录流程:登录页、登录校验、Session 存储、拦截器校验、退出登录。
二、完整实现
1. Controller 层(登录相关)
@Controller
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 跳转到登录页
@GetMapping("/toLogin")
public String toLogin() {
return "login";
}
// 登录校验
@PostMapping("/login")
public String login(String username, String password, HttpSession session, Model model) {
User user = userService.login(username, password);
if (user != null) {
// 登录成功,将用户存入Session
session.setAttribute("loginUser", user);
// 重定向到书籍列表页
return "redirect:/book/all";
} else {
// 登录失败,返回登录页并提示
model.addAttribute("msg", "用户名或密码错误");
return "login";
}
}
// 退出登录
@GetMapping("/logout")
public String logout(HttpSession session) {
// 销毁Session
session.invalidate();
// 重定向到登录页
return "redirect:/user/toLogin";
}
}
2. 登录页(login.jsp)
html
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页</title>
</head>
<body>
<h1>用户登录</h1>
<form action="${pageContext.request.contextPath}/user/login" method="post">
<div style="color: red">${msg}</div>
<div>
用户名:<input type="text" name="username">
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
</body>
</html>
3. 拦截器校验(见 27 章)
拦截器会拦截所有非登录请求,未登录用户自动跳转到登录页,实现登录判断验证。
29、文件上传和下载回顾
一、文件上传
1. 核心依赖与配置
xml
<!-- 文件上传依赖(SpringMVC已集成) -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
SpringMVC 配置文件上传解析器:
xml
<!-- springmvc-servlet.xml -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 最大上传大小:10MB -->
<property name="maxUploadSize" value="10485760"/>
<!-- 编码 -->
<property name="defaultEncoding" value="UTF-8"/>
</bean>
2. Controller 层(文件上传)
java
@Controller
@RequestMapping("/file")
public class FileController {
// 文件上传
@PostMapping("/upload")
public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
// 获取文件名
String fileName = file.getOriginalFilename();
// 获取项目真实路径
String realPath = request.getServletContext().getRealPath("/upload/");
// 创建目录
File dir = new File(realPath);
if (!dir.exists()) {
dir.mkdirs();
}
// 保存文件
file.transferTo(new File(realPath + fileName));
return "redirect:/file/toUpload";
}
}
3. 上传页
html
<form action="${pageContext.request.contextPath}/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
二、文件下载
1. Controller 层(文件下载)
java
@GetMapping("/download")
public ResponseEntity<byte[]> download(String fileName, HttpServletRequest request) throws IOException {
// 获取文件路径
String realPath = request.getServletContext().getRealPath("/upload/");
File file = new File(realPath + fileName);
// 读取文件
byte[] bytes = FileUtils.readFileToByteArray(file);
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentDispositionFormData("attachment", fileName, StandardCharsets.UTF_8);
// 返回文件
return ResponseEntity.ok()
.headers(headers)
.body(bytes);
}
30、总结和展望
一、SSM 全栈知识体系总结
1. MyBatis(持久层)
- 核心:ORM 映射、SQL 与代码分离、动态 SQL、缓存(一级 / 二级)
- 整合:
SqlSessionFactory、MapperScannerConfigurer、事务管理
2. Spring(业务层)
- 核心:IOC/DI、AOP、声明式事务、Bean 管理
- 整合:统一管理数据源、MyBatis 组件、Service 层、事务
3. SpringMVC(Web 层)
- 核心:MVC 架构、
DispatcherServlet、请求映射、参数绑定、视图解析 - 功能:拦截器、文件上传下载、Ajax、登录验证、异常处理
4. SSM 完整架构流转
用户请求 → SpringMVC(Controller,接收请求、参数校验)
↓
Spring(Service,业务逻辑、事务管理、AOP增强)
↓
MyBatis(Mapper,数据库操作、ORM映射)
↓
MySQL(数据库,数据存储、事务执行)
↓
反向响应 → Service → Controller → 视图/JSON → 用户
二、高频面试题汇总
- SpringMVC 的执行流程?
DispatcherServlet拦截请求 →HandlerMapping找 Controller →HandlerAdapter执行方法 → 返回ModelAndView→ViewResolver解析视图 → 渲染响应。
- 拦截器和过滤器的区别?
- 拦截器是 SpringMVC 组件,仅拦截 Controller 请求;过滤器是 Servlet 组件,拦截所有请求。
- Ajax 的核心原理?
- 异步 JavaScript 和 XML,通过
XMLHttpRequest对象异步请求服务器,实现页面局部刷新。
- 异步 JavaScript 和 XML,通过
- SSM 整合的核心是什么?
- 将 MyBatis、SpringMVC 的组件全部交给 Spring 容器统一管理,实现事务、依赖注入的统一控制。
- Spring 声明式事务的原理?
- 基于 AOP 动态代理,在方法执行前后开启、提交 / 回滚事务,无需手动编写事务代码。
三、技术学习展望
- SpringBoot:零 XML 配置,快速开发,是 SSM 的升级替代方案
- MyBatis-Plus:MyBatis 增强工具,简化 CRUD,提升开发效率
- SpringCloud:微服务架构,实现分布式系统开发
- 前后端分离:Vue/React + SpringBoot,纯 RESTful API 开发
- 容器化部署:Docker + Kubernetes,实现项目快速部署与运维