Spring MVC笔记
01 什么是Spring MVC
Spring MVC 是 Spring 框架中的一个核心模块,专门用于构建 Web 应用程序。它基于经典的 MVC 设计模式(Model-View-Controller),但通过 Spring 的特性(如依赖注入、注解驱动)大幅简化了开发流程。
Spring MVC 是什么?
- 本质:
 一个基于 Java 的 Web 框架,帮助开发者快速、结构化地开发动态网站或 RESTful API。
- 核心思想:
 将应用程序拆分为 模型(Model)、视图(View)、控制器(Controller) 三个部分,实现职责分离,让代码更易维护和扩展。
Spring MVC 的作用
1. 处理用户请求和响应
• 用户通过浏览器发送请求(如点击链接、提交表单),Spring MVC 的控制器(Controller)接收请求,处理业务逻辑,最终返回响应(如 HTML 页面、JSON 数据)。
2. 解耦代码,分工协作
• Model(模型):负责数据和业务逻辑(如数据库操作)。
 • View(视图):负责展示数据(如 HTML、JSP、Thymeleaf 模板)。
 • Controller(控制器):负责协调用户请求、调用模型、返回视图。
 • 三者独立开发,修改某一层不会影响其他层。
3. 简化传统 Servlet 开发
• 传统 Servlet 需要手动处理 HTTP 请求参数、响应输出等底层细节,代码臃肿。
 • Spring MVC 通过 注解(如 @RequestMapping) 和 自动绑定 机制,让开发者专注业务逻辑。
 • 例如,直接通过注解将请求参数绑定到 Java 对象:
 @PostMapping("/user")public String createUser(User user) {  // 自动将表单参数封装到User对象userService.save(user);return "success";}
4. 灵活适配多种技术
• 视图技术:支持 JSP、Thymeleaf、FreeMarker 等模板引擎,甚至直接返回 JSON(适合前后端分离)。
 • 数据交互:轻松处理 JSON、XML 等数据格式(配合 @RestController)。
 • 整合其他框架:无缝集成 Spring Security(安全)、Spring Data(数据库)等模块。
5. 强大的扩展性
• 通过拦截器(Interceptor)、全局异常处理(@ControllerAdvice)等机制,可以统一处理日志、权限、异常等问题。
 • 例如,全局拦截未登录用户:
 public class AuthInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {if (user未登录) {response.sendRedirect("/login");return false;}return true;}}
02 创建Spring MVC项目
以下是两种常用的 Spring MVC 项目搭建方式(传统 XML 配置和Spring Boot 快速搭建):
一、传统方式:基于 Maven + XML 配置(适合学习底层原理)
1. 创建 Maven 项目
2. 添加依赖(pom.xml)
 
<!-- Spring MVC 核心依赖 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.29</version>
</dependency><!-- Servlet API -->
<dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope>
</dependency><!-- JSP 支持 -->
<dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version><scope>provided</scope>
</dependency>
3. 配置 web.xml(初始化 DispatcherServlet)
 
<web-app><!-- 配置前端控制器 DispatcherServlet --><servlet><servlet-name>dispatcher</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></init-param><load-on-startup>1</load-on-startup></servlet><!-- 映射所有请求到 DispatcherServlet --><servlet-mapping><servlet-name>dispatcher</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>
4. 创建 Spring MVC 配置文件(/WEB-INF/spring-mvc.xml)
 
<!-- 开启注解驱动 -->
<mvc:annotation-driven/><!-- 配置视图解析器(JSP) -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/>
</bean><!-- 扫描 Controller 包 -->
<context:component-scan base-package="com.example.controller"/>
5. 创建 Controller 和 JSP 视图
// com.example.controller.HomeController.java
@Controller
public class HomeController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello Spring MVC!");return "hello"; // 对应 /WEB-INF/views/hello.jsp}
}
<%-- /WEB-INF/views/hello.jsp --%>
<html>
<body><h1>${message}</h1>
</body>
</html>
6. 部署到 Tomcat
• 将项目打包为 WAR 文件,部署到 Tomcat 服务器,访问 http://localhost:8080/项目名/hello。
二、快速方式:基于 Spring Boot
1. 使用 Spring Initializr 创建项目
• 访问 https://start.spring.io,选择:
 • 依赖:Spring Web(已包含 Spring MVC)、Thymeleaf(模板引擎)。
 • 打包方式:JAR(内嵌 Tomcat,无需手动部署)。
2. 项目结构
src/main/java/com.example.demo/DemoApplication.java  // 启动类controller/HomeController.javaresources/templates/  // 存放视图(如HTML)static/     // 存放静态资源(CSS/JS)
3. 编写 Controller
@Controller
public class HomeController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello Spring Boot MVC!");return "hello"; // 对应 resources/templates/hello.html}
}
4. 创建视图(Thymeleaf)
<!-- resources/templates/hello.html -->
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body><h1 th:text="${message}"></h1>
</body>
</html>
5. 运行项目
• 直接运行 DemoApplication.java 的 main 方法,访问 http://localhost:8080/hello。
三、关键配置说明
-  视图解析器: 
 • 传统方式需手动配置 JSP 路径(如/WEB-INF/views/*.jsp)。
 • Spring Boot 默认使用templates目录存放视图(需配合模板引擎如 Thymeleaf)。
-  静态资源访问: 
 • Spring Boot 默认将static目录下的文件映射为静态资源(如http://localhost:8080/css/style.css)。
 • 传统方式需在 XML 中配置<mvc:resources location="/static/" mapping="/static/**"/>。
四、常见问题
-  404 错误: 
 • 检查 Controller 是否被扫描(@ComponentScan包路径是否正确)。
 • 视图文件是否放在正确目录(如templates或WEB-INF/views)。
-  依赖冲突: 
 • 确保 Spring 版本与依赖库兼容(推荐使用 Spring Boot 自动管理版本)。
03 Spring MVC执行原理
Spring MVC 的执行原理基于前端控制器模式,其核心是 DispatcherServlet,负责协调各组件处理请求。
1. 请求接收
• 用户发起请求:客户端(浏览器)发送HTTP请求至Web应用。
 • 前端控制器接管:请求首先被 DispatcherServlet(配置在 web.xml 中)拦截,作为统一入口处理所有请求。
2. 处理器映射(Handler Mapping)
• 查找处理器:DispatcherServlet 通过 HandlerMapping 根据请求URL(如 /hello)找到对应的处理器(Handler),通常是@Controller 中标注 @RequestMapping 的方法。
 • 返回处理器链:可能包含拦截器(Interceptor)和具体的控制器方法。
3. 处理器适配器(Handler Adapter)
• 执行处理器:HandlerAdapter 调用具体的处理器方法(如 @GetMapping 方法),处理不同形式的控制器(如基于注解或实现 Controller 接口)。
 • 参数解析与绑定:方法参数通过 ArgumentResolver 解析(如请求参数、模型、@PathVariable 等)。
 • 数据转换/验证:使用 Converter、Validator 进行类型转换和数据校验。
4. 控制器处理
• 业务逻辑执行:控制器方法调用Service层处理业务,返回结果(如 String 视图名、ModelAndView 或 @ResponseBody 数据)。
 • 模型数据填充:将数据存储在 Model 对象中,供视图渲染使用。
5. 视图解析(View Resolution)
• 解析视图名:ViewResolver 根据控制器返回的视图名(如 "home")解析为具体的 View 对象(如JSP、Thymeleaf模板)。
 • 示例配置:InternalResourceViewResolver 可能将 "home" 映射到 /WEB-INF/views/home.jsp。
6. 视图渲染
• 模型数据传递:DispatcherServlet 将模型数据传递给 View 对象。
 • 生成响应内容:视图使用模板引擎(如JSP、Freemarker)渲染HTML,写入HTTP响应。
7. 返回响应
• 响应客户端:渲染后的内容通过 DispatcherServlet 返回给客户端,完成请求-响应周期。
关键组件与扩展点
• 拦截器(Interceptor):在请求处理前后执行逻辑(如权限检查、日志记录),通过实现 HandlerInterceptor 接口配置。
 • 异常处理:@ExceptionHandler 或 HandlerExceptionResolver 统一处理控制器抛出的异常。
 • 文件上传:MultipartResolver 解析 multipart 请求(如文件上传)。
执行流程图示
客户端 → DispatcherServlet → HandlerMapping → HandlerAdapter → Controller → ModelAndView → ViewResolver → View → 响应
示例配置
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {// 视图解析器@Beanpublic ViewResolver viewResolver() {InternalResourceViewResolver resolver = new InternalResourceViewResolver();resolver.setPrefix("/WEB-INF/views/");resolver.setSuffix(".jsp");return resolver;}// 静态资源处理@Overridepublic void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();}
}@Controller
public class HelloController {@GetMapping("/hello")public String hello(Model model) {model.addAttribute("message", "Hello Spring MVC!");return "hello"; // 对应 /WEB-INF/views/hello.jsp}
}
04 RequestMapping
在 Spring MVC 中,@RequestMapping 是一个核心注解,用于将 HTTP 请求映射到特定的控制器方法。它提供了灵活的配置选项,支持定义请求路径、HTTP 方法、请求参数、请求头等条件。以下是其详细用法和功能说明:
1. 基本作用
• 定义请求映射规则:将 URL 请求路径与控制器方法绑定。
 • 支持多种请求类型:GET、POST、PUT、DELETE 等。
 • 支持路径变量、参数过滤、请求头过滤等高级条件。
2. 可用位置
• 类级别:定义共享的根路径(所有方法映射路径会继承该路径)。
 • 方法级别:定义具体方法的映射规则。
示例
@Controller
@RequestMapping("/user") // 类级别路径:所有方法映射路径以 /user 开头
public class UserController {// 实际路径:/user/profile@RequestMapping("/profile")public String profile() { ... }// 实际路径:/user/list@RequestMapping("/list")public String list() { ... }
}
3. 核心属性
(1) value 或 path
 
• 定义请求路径:支持字符串或字符串数组(允许多路径映射)。
 • 支持路径变量({variable})和通配符(*, **)。
// 单路径
@RequestMapping("/detail")// 多路径映射
@RequestMapping({"/info", "/detail"})// 路径变量
@RequestMapping("/user/{id}")
public String getUser(@PathVariable Long id) { ... }// 通配符匹配(如 /user/2023/order)
@RequestMapping("/user/*/order")
(2) method
 
• 指定允许的 HTTP 方法:如 RequestMethod.GET, RequestMethod.POST。
 • 默认支持所有 HTTP 方法。
// 只允许 GET 请求
@RequestMapping(value = "/list", method = RequestMethod.GET)// 允许多个 HTTP 方法
@RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.PUT})
(3) params
 
• 过滤请求参数:要求请求必须包含指定参数,或参数满足特定条件。
 • 格式:param(必须存在)、!param(必须不存在)、param=value(值匹配)。
// 要求请求必须包含 id 参数
@RequestMapping(params = "id")// 要求必须包含 id 且值为 100
@RequestMapping(params = "id=100")// 要求不能包含 debug 参数
@RequestMapping(params = "!debug")
(4) headers
 
• 过滤请求头:要求请求头满足特定条件。
 • 格式与 params 类似。
// 要求请求头包含 Content-Type=application/json
@RequestMapping(headers = "Content-Type=application/json")// 要求请求头必须包含 Auth-Token
@RequestMapping(headers = "Auth-Token")
(5) consumes
 
• 指定请求的 Content-Type:要求请求体的媒体类型匹配。
// 仅处理 Content-Type 为 application/json 的请求
@RequestMapping(consumes = "application/json")
(6) produces
 
• 指定响应的 Content-Type:设置响应体的媒体类型。
// 返回 JSON 数据
@RequestMapping(produces = "application/json")
4. 组合注解
为了简化代码,Spring 提供了基于 @RequestMapping 的快捷组合注解:
| 组合注解 | 等效写法 | 作用 | 
|---|---|---|
| @GetMapping | @RequestMapping(method = RequestMethod.GET) | 处理 GET 请求 | 
| @PostMapping | @RequestMapping(method = RequestMethod.POST) | 处理 POST 请求 | 
| @PutMapping | @RequestMapping(method = RequestMethod.PUT) | 处理 PUT 请求 | 
| @DeleteMapping | @RequestMapping(method = RequestMethod.DELETE) | 处理 DELETE 请求 | 
| @PatchMapping | @RequestMapping(method = RequestMethod.PATCH) | 处理 PATCH 请求 | 
示例
@GetMapping("/user/{id}") // 等价于 @RequestMapping(value="/user/{id}", method=RequestMethod.GET)
public String getUser(@PathVariable Long id) { ... }
5. 路径匹配规则
(1) 路径变量({variable})
 
• 使用 @PathVariable 获取路径中的动态值。
// 匹配路径如 /user/123
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Long userId) { ... }
(2) 通配符
• ?:匹配单个字符(如 /user/2023? 匹配 /user/2023a)。
 • *:匹配同一层级的任意字符(如 /user/*/order 匹配 /user/123/order)。
 • **:匹配多层路径(如 /user/** 匹配 /user/123/order/456)。
(3) 正则表达式
• 路径变量中可使用正则表达式限制格式。
// 限制 id 必须为数字
@GetMapping("/user/{id:\\d+}")
public String getUser(@PathVariable Long id) { ... }
6. 示例代码
(1) 完整控制器
@Controller
@RequestMapping("/product")
public class ProductController {// 匹配 GET /product/detail?id=100@GetMapping(value = "/detail", params = "id")public String detail(@RequestParam Long id, Model model) {model.addAttribute("product", productService.findById(id));return "product/detail";}// 匹配 POST 或 PUT /product/save@RequestMapping(value = "/save", method = {RequestMethod.POST, RequestMethod.PUT})public String saveProduct(@ModelAttribute Product product) {productService.save(product);return "redirect:/product/list";}// 路径变量 + 正则匹配(如 /product/category/electronics)@GetMapping("/category/{type:[a-z]+}")public String listByCategory(@PathVariable String type, Model model) {model.addAttribute("products", productService.findByCategory(type));return "product/list";}
}
05 Resful风格
RESTful(REpresentational State Transfer)是一种基于 HTTP 协议的 API 设计风格,强调以资源为中心,通过统一的接口和标准方法(GET/POST/PUT/DELETE 等)操作资源。
一、RESTful 的核心原则
-  资源(Resource) 
 • 所有数据或服务抽象为资源(如用户、订单),通过 URI(统一资源标识符) 唯一标识。
 • 示例:/users(用户集合)、/users/1001(ID 为 1001 的用户)。
-  统一接口(Uniform Interface) 
 • 使用标准的 HTTP 方法 操作资源:
 ◦ GET:获取资源
 ◦ POST:创建资源
 ◦ PUT:更新资源(全量替换)
 ◦ PATCH:部分更新资源
 ◦ DELETE:删除资源
-  无状态(Stateless) 
 • 服务端不保存客户端状态,每个请求必须包含所有必要信息。
-  表述(Representation) 
 • 资源的表现形式(如 JSON、XML),客户端通过 HTTP 头(Accept/Content-Type)协商格式。
-  超媒体驱动(HATEOAS) 
 • 响应中包含相关资源的链接,客户端通过链接导航(可选约束,实际使用较少)。
二、RESTful API 设计规范
1. URI 设计规范
• 使用名词,而非动词:URI 表示资源,动作由 HTTP 方法表达。
❌ 非 RESTful: /getUser?id=1001  
✅ RESTful: GET /users/1001
• 层级关系使用 / 分隔:
GET /users/1001/orders  # 获取用户 1001 的所有订单
• 复数形式命名集合:
GET /users       # 用户集合
POST /users      # 创建用户
• 过滤、排序、分页通过查询参数实现:
GET /users?page=2&size=10&sort=name,asc  # 分页排序
GET /users?name=John&age=30              # 过滤
2. HTTP 方法使用规范
| HTTP 方法 | 操作类型 | 幂等性 | 示例 | 
|---|---|---|---|
| GET | 查询资源 | 是 | GET /users/1001 | 
| POST | 创建资源 | 否 | POST /users | 
| PUT | 全量更新 | 是 | PUT /users/1001 | 
| PATCH | 部分更新 | 否 | PATCH /users/1001 | 
| DELETE | 删除资源 | 是 | DELETE /users/1001 | 
3. 状态码(Status Code)
• 2xx:成功
 • 200 OK:常规成功
 • 201 Created:资源创建成功
 • 204 No Content:成功但无返回体(如删除操作)
• 4xx:客户端错误
 • 400 Bad Request:请求参数错误
 • 401 Unauthorized:未认证
 • 403 Forbidden:无权限
 • 404 Not Found:资源不存在
• 5xx:服务端错误
 • 500 Internal Server Error:服务器内部错误
4. 数据格式
• 使用 JSON 作为主流数据交换格式。
 • 请求头指定 Content-Type: application/json。
 • 响应头包含 Content-Type: application/json。
三、在 Spring 中实现 RESTful API
1. 使用 @RestController 注解
 
• 替代 @Controller + @ResponseBody,直接返回 JSON 数据。
@RestController
@RequestMapping("/api/users")
public class UserController {// ...
}
2. 映射 HTTP 方法
• 使用组合注解:@GetMapping, @PostMapping, @PutMapping, @DeleteMapping。
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) { ... }
3. 处理请求和响应
• 路径变量:@PathVariable
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) { ... }
• 请求体:@RequestBody
@PostMapping
public User createUser(@RequestBody User user) { ... }
• 返回 ResponseEntity:自定义状态码和响应头
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {User savedUser = userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);
}
4. 统一异常处理
• 使用 @ExceptionHandler 和 @ControllerAdvice 返回标准错误响应。
@ControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(ResourceNotFoundException.class)public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException e) {ErrorResponse error = new ErrorResponse(404, e.getMessage());return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);}
}
四、完整示例
1. 实体类
public class User {private Long id;private String name;private String email;// Getters and Setters
}
2. 控制器
@RestController
@RequestMapping("/api/users")
public class UserController {@Autowiredprivate UserService userService;// 获取所有用户@GetMappingpublic List<User> getAllUsers() {return userService.findAll();}// 创建用户@PostMappingpublic ResponseEntity<User> createUser(@RequestBody User user) {User savedUser = userService.save(user);return ResponseEntity.status(HttpStatus.CREATED).body(savedUser);}// 获取单个用户@GetMapping("/{id}")public User getUser(@PathVariable Long id) {return userService.findById(id).orElseThrow(() -> new ResourceNotFoundException("User not found"));}// 更新用户(全量)@PutMapping("/{id}")public User updateUser(@PathVariable Long id, @RequestBody User user) {user.setId(id);return userService.update(user);}// 删除用户@DeleteMapping("/{id}")@ResponseStatus(HttpStatus.NO_CONTENT)public void deleteUser(@PathVariable Long id) {userService.deleteById(id);}
}
3. 请求与响应示例
• 请求:POST /api/users
{"name": "Alice","email": "alice@example.com"
}
• 响应(状态码 201):
{"id": 1001,"name": "Alice","email": "alice@example.com"
}
06 重定向和转发
在 Spring MVC 中,重定向(Redirect) 和 转发(Forward) 是两种不同的请求跳转方式,理解它们的区别和适用场景对开发至关重要。以下是详细对比及具体用法:
一、核心区别
| 特性 | 转发(Forward) | 重定向(Redirect) | 
|---|---|---|
| 发起方 | 服务端内部跳转(客户端无感知) | 服务端通知客户端重新发起请求 | 
| 请求次数 | 1 次请求,1 次响应 | 2 次请求,2 次响应 | 
| 地址栏变化 | 地址栏 URL 不变 | 地址栏 URL 变为目标地址 | 
| 数据共享 | 共享同一 Request 作用域( request.setAttribute) | 不共享 Request 作用域,需通过 URL 参数或 Session 传递 | 
| 性能 | 更高(无额外请求) | 较低(多一次网络往返) | 
| 使用场景 | 服务器内部资源跳转(如 JSP 间共享数据) | 跨应用跳转、防止表单重复提交(POST-REDIRECT-GET) | 
二、在 Spring MVC 中的实现方式
1. 转发(Forward)
• 原理:服务端内部将请求转发到另一个资源(如 JSP、控制器方法)。
 • 语法:在返回值前加 forward: 前缀。
 • 示例:
@GetMapping("/page1")
public String forwardDemo() {// 转发到 /page2(客户端 URL 仍为 /page1)return "forward:/page2";
}@GetMapping("/page2")
public String page2() {return "page2"; // 视图名对应视图解析器路径
}
• 数据传递:通过 Model 或 HttpServletRequest 传递数据。
@GetMapping("/forward")
public String forward(Model model) {model.addAttribute("message", "Hello from forward!");return "forward:/targetPage";
}
2. 重定向(Redirect)
• 原理:服务端返回 302 状态码和 Location 头,客户端自动发起新请求。
 • 语法:在返回值前加 redirect: 前缀。
 • 示例:
@PostMapping("/submit")
public String submitForm(FormData formData, RedirectAttributes redirectAttributes) {// 处理表单数据...// 重定向到 /result,传递参数redirectAttributes.addAttribute("status", "success");redirectAttributes.addFlashAttribute("message", "操作成功!");return "redirect:/result";
}@GetMapping("/result")
public String resultPage(@RequestParam String status, Model model) {// 接收 URL 参数和 Flash 属性return "result";
}
• 数据传递:
 • URL 参数:RedirectAttributes.addAttribute("key", value) → 参数暴露在 URL 中。
 • Flash 属性:RedirectAttributes.addFlashAttribute("key", value) → 数据暂存 Session,一次请求后自动删除。
三、适用场景
1. 转发(Forward)
• 共享请求数据:需要在多个视图或控制器间传递数据(如 JSP 到 JSP)。
 • 隐藏实际资源路径:保护内部资源路径,客户端无法直接访问。
 • 统一预处理:在转发前进行权限验证、日志记录等。
2. 重定向(Redirect)
• 防止表单重复提交:提交后重定向到结果页(POST-REDIRECT-GET 模式)。
 • 跨应用跳转:跳转到外部网站或其他服务。
 • 切换上下文路径:如从 HTTP 跳转到 HTTPS,或更换域名。
五、完整代码示例
1. 转发示例
@Controller
public class ForwardController {@GetMapping("/source")public String sourcePage(Model model) {model.addAttribute("data", "来自源页面的数据");return "forward:/target"; // 转发到 /target}@GetMapping("/target")public String targetPage(Model model) {// 可以访问 model 中的 datareturn "target-page"; // 视图模板路径}
}
2. 重定向示例
@Controller
public class RedirectController {@PostMapping("/save")public String saveData(User user, RedirectAttributes redirectAttributes) {userService.save(user);// 添加 URL 参数(暴露在地址栏)redirectAttributes.addAttribute("userId", user.getId());// 添加 Flash 属性(安全传递敏感数据)redirectAttributes.addFlashAttribute("message", "用户保存成功!");return "redirect:/user/detail";}@GetMapping("/user/detail")public String userDetail(@RequestParam Long userId, Model model) {User user = userService.findById(userId);model.addAttribute("user", user);return "user-detail";}
}
六、总结
• 转发(Forward):适合服务器内部资源跳转,共享请求数据,性能更高。
 • 重定向(Redirect):适合客户端跳转、防止重复提交,需注意数据传递方式。
 • 开发建议:
 • 表单提交后 必须使用重定向 避免重复提交。
 • 优先使用 RedirectAttributes 传递数据,避免 URL 参数暴露敏感信息。
07 接收请求参数和数据回显
一、接收请求参数
1. 基本参数接收
• @RequestParam:获取 URL 参数或表单字段(默认必传,可设 required=false)。
@GetMapping("/user")
public String getUser(@RequestParam("id") Long userId, @RequestParam(value = "name", defaultValue = "Guest") String userName) {// URL: /user?id=1001&name=Alice// userId=1001, userName=Alice(若未传name,默认为"Guest")return "user/detail";
}
• @PathVariable:获取 URL 路径变量。
@GetMapping("/user/{id}")
public String getUser(@PathVariable("id") Long userId) {// URL: /user/1001 → userId=1001return "user/detail";
}
2. 对象自动绑定
• @ModelAttribute:自动将表单字段绑定到对象(支持级联属性)。
@PostMapping("/save")
public String saveUser(@ModelAttribute User user) {// 表单字段 name 和 email 自动绑定到 User 对象userService.save(user);return "redirect:/user/list";
}
• 无需注解:直接声明对象参数,Spring 自动绑定。
@PostMapping("/save")
public String saveUser(User user) { // 效果同上userService.save(user);return "redirect:/user/list";
}
3. 接收 JSON 数据
• @RequestBody:将请求体中的 JSON 反序列化为对象。
@PostMapping("/api/user")
@ResponseBody
public ResponseEntity<User> createUser(@RequestBody User user) {User savedUser = userService.save(user);return ResponseEntity.ok(savedUser);
}
4. 接收原生对象
• 直接使用 HttpServletRequest、HttpSession 等原生对象。
@GetMapping("/info")
public String getInfo(HttpServletRequest request, HttpSession session) {String param = request.getParameter("param");session.setAttribute("key", "value");return "info";
}
二、数据回显(传递到视图)
1. 使用 Model 或 ModelMap
 
• 添加数据到模型,供视图(如 JSP、Thymeleaf)渲染。
@GetMapping("/user/edit")
public String editUser(@RequestParam Long id, Model model) {User user = userService.findById(id);model.addAttribute("user", user); // 回显到表单return "user/edit";
}
2. 使用 ModelAndView
 
• 同时返回视图名和数据。
@GetMapping("/user/detail")
public ModelAndView userDetail(@RequestParam Long id) {ModelAndView mav = new ModelAndView("user/detail");User user = userService.findById(id);mav.addObject("user", user);return mav;
}
08 JSON
在 Spring 生态中,JSON(JavaScript Object Notation) 是主流的轻量级数据交换格式,而 Jackson 是处理 JSON 序列化与反序列化的核心库。
一、JSON 简介
1. 什么是 JSON?
• 轻量级数据格式:以键值对(key: value)形式组织数据,易读且兼容性强。
 • 数据结构:
 • 对象:{ "key": value }
 • 数组:[ value1, value2 ]
 • 值类型:字符串、数字、布尔值、null、对象、数组。
2. 应用场景
• 前后端数据交互:API 请求和响应。
 • 配置文件(如 package.json)。
 • NoSQL 数据库(如 MongoDB)存储格式。
3. 对比 XML
| 特性 | JSON | XML | 
|---|---|---|
| 可读性 | 高(结构简洁) | 较低(标签冗余) | 
| 数据体积 | 更小 | 更大 | 
| 解析速度 | 更快 | 较慢 | 
| 扩展性 | 弱(无命名空间、属性等概念) | 强(支持复杂结构) | 
二、Jackson 核心功能
Jackson 是 Java 生态中最流行的 JSON 处理库,提供以下能力:
- 序列化:将 Java 对象转换为 JSON 字符串。
- 反序列化:将 JSON 字符串解析为 Java 对象。
- 数据绑定:支持注解驱动配置。
- 流式 API:高性能处理大 JSON 数据。
三、Spring 中集成 Jackson
Spring MVC 默认通过 MappingJackson2HttpMessageConverter 集成 Jackson,自动处理 JSON 转换。
1. 添加依赖
<!-- Maven 依赖 -->
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version>
</dependency>
2. 启用 JSON 支持
• 注解驱动:使用 @RestController 或 @ResponseBody。
@RestController // 等效于 @Controller + @ResponseBody
@RequestMapping("/api/users")
public class UserController {@GetMapping("/{id}")public User getUser(@PathVariable Long id) {return userService.findById(id);}
}
四、Jackson 核心注解
通过注解控制序列化/反序列化行为:
1. 字段映射
• @JsonProperty:指定 JSON 字段名。
public class User {@JsonProperty("user_name")private String name;
}
// 序列化为 { "user_name": "Alice" }
• @JsonIgnore:忽略字段。
public class User {@JsonIgnoreprivate String password;
}
2. 日期格式化
• @JsonFormat:自定义日期格式。
public class Order {@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private LocalDateTime createTime;
}
// 序列化为 "2023-10-01 14:30:00"
3. 空值处理
• @JsonInclude:忽略空值字段。
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {private String email; // 若 email 为 null,不序列化
}
五、序列化与反序列化示例
1. Java 对象转 JSON(序列化)
ObjectMapper mapper = new ObjectMapper();
User user = new User("Alice", 30);
String json = mapper.writeValueAsString(user);
// 输出:{"name":"Alice","age":30}
2. JSON 转 Java 对象(反序列化)
String json = "{\"name\":\"Alice\",\"age\":30}";
User user = mapper.readValue(json, User.class);
六、Spring 中高级配置
1. 自定义 ObjectMapper
@Configuration
public class JacksonConfig {@Beanpublic ObjectMapper objectMapper() {ObjectMapper mapper = new ObjectMapper();mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);return mapper;}
}
七、常见问题与解决方案
1. 日期格式不生效
• 问题:日期字段未按预期格式序列化。
 • 解决:检查 @JsonFormat 的 timezone 配置或全局 ObjectMapper 日期格式。
2. 字段丢失
• 问题:JSON 中缺少字段导致反序列化失败。
 • 解决:配置 ObjectMapper 忽略未知字段:
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
09 Fastjson
在 Java 开发中,Fastjson 是阿里巴巴开源的高性能 JSON 库,广泛用于序列化(Java 对象转 JSON)和反序列化(JSON 转 Java 对象)。与 Jackson 相比,Fastjson 在部分场景下性能更优,且 API 设计更简单易用。以下是其核心特性、使用方式及注意事项:
一、Fastjson 核心特性
-  高性能 
 • 序列化/反序列化速度极快,尤其在大数据量场景下表现优异。
 • 依赖 ASM 字节码技术优化(无需反射),性能优于 Jackson 和 Gson。
-  功能丰富 
 • 支持复杂对象(泛型、嵌套对象、循环引用)。
 • 支持 Java 8 时间 API(如LocalDateTime)。
 • 支持自定义序列化规则和过滤器。
-  简单 API 
 • 核心类JSON提供静态方法(如JSON.toJSONString()、JSON.parseObject())。
-  注解驱动 
 • 通过@JSONField注解灵活控制字段映射和格式。
二、与 Jackson 对比
| 特性 | Fastjson | Jackson | 
|---|---|---|
| 性能 | 更高(尤其序列化) | 较高 | 
| 安全性 | 历史漏洞较多(需使用最新版本) | 安全性较好 | 
| API 简洁性 | 极简(静态方法) | 稍复杂(需 ObjectMapper实例) | 
| 社区生态 | 国内流行,文档丰富 | 国际主流,生态更成熟 | 
| 维护状态 | 阿里巴巴维护,更新频繁 | 长期稳定更新 | 
三、Spring 中集成 Fastjson
Spring Boot 默认使用 Jackson,若需替换为 Fastjson,需手动配置消息转换器。
1. 添加依赖
<!-- Maven 依赖 -->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.34</version> <!-- 使用最新版本(避免安全漏洞) -->
</dependency>
2. 配置 Fastjson 消息转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {// 创建 Fastjson 消息转换器FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();// 配置序列化规则FastJsonConfig config = new FastJsonConfig();config.setSerializerFeatures(SerializerFeature.PrettyFormat,       // 格式化输出SerializerFeature.WriteMapNullValue,  // 输出空值字段SerializerFeature.WriteDateUseDateFormat // 日期格式化);config.setDateFormat("yyyy-MM-dd HH:mm:ss");converter.setFastJsonConfig(config);// 处理中文乱码List<MediaType> mediaTypes = new ArrayList<>();mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);converter.setSupportedMediaTypes(mediaTypes);// 替换默认 Jackson 转换器converters.add(0, converter);}
}
四、核心 API 使用示例
1. 序列化(Java → JSON)
User user = new User("Alice", 25, LocalDateTime.now());// 简单序列化
String json = JSON.toJSONString(user); 
// 输出:{"age":25,"name":"Alice","createTime":"2023-10-01 14:30:00"}// 带格式化的序列化
String prettyJson = JSON.toJSONString(user, SerializerFeature.PrettyFormat);
2. 反序列化(JSON → Java)
String json = "{\"name\":\"Bob\",\"age\":30}";// 基本反序列化
User user = JSON.parseObject(json, User.class);// 处理泛型(如 List)
String listJson = "[{\"name\":\"Alice\"}, {\"name\":\"Bob\"}]";
List<User> users = JSON.parseArray(listJson, User.class);
五、注解 @JSONField
 
通过注解控制字段的序列化行为:
1. 字段重命名
public class User {@JSONField(name = "user_name")private String name; // 序列化为 "user_name"
}
2. 忽略字段
public class User {@JSONField(serialize = false)private String password; // 不序列化
}
3. 日期格式化
public class User {@JSONField(format = "yyyy-MM-dd")private LocalDate birthDate;
}
4. 顺序控制
@JSONType(orders = {"id", "name", "age"}) // 类级别定义字段顺序
public class User {private Long id;private String name;private Integer age;
}
10 ssm整合项目搭建
Spring MVC 图书管理系统开发流程与示例
一、项目目录结构(简化版)
src/
├── main/
│   ├── java/
│   │   └── com/
│   │       └── example/
│   │           ├── controller/    # 控制器层
│   │           │   └── BookController.java
│   │           ├── dao/          # DAO层(MyBatis Mapper接口)
│   │           │   └── BookMapper.java
│   │           ├── service/      # 业务层
│   │           │   ├── BookService.java
│   │           │   └── impl/
│   │           │       └── BookServiceImpl.java
│   │           └── entity/       # 实体类
│   │               └── Book.java
│   └── resources/
│       ├── mapper/               # MyBatis Mapper XML
│       │   └── BookMapper.xml
│       ├── spring/              # Spring配置
│       │   ├── spring.xml
│       │   └── spring-mvc.xml
│       └── jdbc.properties      # 数据库配置
webapp/
├── WEB-INF/
│   └── views/                   # JSP视图
│       └── book/
│           └── list.jsp
└── index.jsp
二、开发流程与代码示例
1. 创建数据库表
CREATE TABLE book (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(100) NOT NULL,author VARCHAR(50),price DECIMAL(10,2)
);
2. 实体类 Book.java(POJO层)
 
package com.example.entity;public class Book {private Integer id;private String name;private String author;private Double price;// Getters and Setters
}
3. DAO层接口 BookMapper.java
 
package com.example.dao;import com.example.entity.Book;
import java.util.List;public interface BookMapper {List<Book> selectAll();int insert(Book book);int deleteById(Integer id);
}
4. MyBatis Mapper XML BookMapper.xml
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.BookMapper"><select id="selectAll" resultType="Book">SELECT id, name, author, price FROM book</select><insert id="insert" parameterType="Book">INSERT INTO book(name, author, price)VALUES(#{name}, #{author}, #{price})</insert><delete id="deleteById" parameterType="Integer">DELETE FROM book WHERE id = #{id}</delete>
</mapper>
5. Service层实现业务逻辑
// 接口 BookService.java
package com.example.service;
import com.example.entity.Book;
import java.util.List;public interface BookService {List<Book> listBooks();void addBook(Book book);void deleteBook(Integer id);
}// 实现类 BookServiceImpl.java
package com.example.service.impl;import com.example.dao.BookMapper;
import com.example.entity.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookMapper bookMapper;@Overridepublic List<Book> listBooks() {return bookMapper.selectAll();}@Override@Transactionalpublic void addBook(Book book) {bookMapper.insert(book);}@Override@Transactionalpublic void deleteBook(Integer id) {bookMapper.deleteById(id);}
}
6. Controller层处理请求
package com.example.controller;import com.example.entity.Book;
import com.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;@Controller
@RequestMapping("/book")
public class BookController {@Autowiredprivate BookService bookService;// 查询所有书籍@GetMapping("/list")public String listBooks(Model model) {model.addAttribute("books", bookService.listBooks());return "book/list";}// 添加书籍(表单提交)@PostMapping("/add")public String addBook(Book book) {bookService.addBook(book);return "redirect:/book/list";}// 删除书籍@GetMapping("/delete/{id}")public String deleteBook(@PathVariable Integer id) {bookService.deleteBook(id);return "redirect:/book/list";}
}
7. 配置文件
(1) jdbc.properties
 
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/book_db?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
(2) spring.xml(Spring核心配置)
 
<!-- 数据源 -->
<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><!-- MyBatis SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><property name="dataSource" ref="dataSource"/><property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean><!-- Mapper接口扫描 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.example.dao"/>
</bean><!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/>
</bean><!-- 开启注解扫描 -->
<context:component-scan base-package="com.example.service"/>
(3) spring-mvc.xml(Spring MVC配置)
 
<!-- 注解驱动 -->
<mvc:annotation-driven/><!-- 视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/>
</bean><!-- 扫描控制器 -->
<context:component-scan base-package="com.example.controller"/><!-- 静态资源处理 -->
<mvc:resources mapping="/static/**" location="/static/"/>
8. 视图层 list.jsp
 
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head><title>图书列表</title>
</head>
<body><h2>图书列表</h2><table border="1"><tr><th>ID</th><th>书名</th><th>作者</th><th>价格</th><th>操作</th></tr><c:forEach items="${books}" var="book"><tr><td>${book.id}</td><td>${book.name}</td><td>${book.author}</td><td>${book.price}</td><td><a href="/book/delete/${book.id}">删除</a></td></tr></c:forEach></table><h3>添加新书</h3><form action="/book/add" method="post">书名:<input type="text" name="name"><br>作者:<input type="text" name="author"><br>价格:<input type="number" step="0.01" name="price"><br><button type="submit">提交</button></form>
</body>
</html>
三、关键流程说明
-  请求处理流程 浏览器请求 → DispatcherServlet → BookController → BookService → BookMapper → 数据库
-  分层职责 
 • DAO层:直接操作数据库,提供insert、delete等方法。
 • Service层:处理业务逻辑(如事务管理@Transactional)。
 • Controller层:接收HTTP请求,返回视图或重定向。
四、启动与测试
- 部署到Tomcat,访问 http://localhost:8080/book/list。
- 添加图书:填写表单提交,数据插入数据库。
- 删除图书:点击删除链接,触发 DELETE操作。
11 整合SSM框架的配置文件
SSM 整合核心配置文件详解
以下是整合 Spring、Spring MVC 和 MyBatis(SSM)时 必须配置的核心内容,分步骤说明每个配置文件的作用和关键配置项。
一、项目结构
src/
├── main/
│   ├── java/
│   │   └── com/example/
│   │       ├── controller/   # Spring MVC 控制器
│   │       ├── service/      # 业务层接口和实现
│   │       ├── dao/          # MyBatis Mapper 接口
│   │       └── entity/       # 数据库实体类
│   └── resources/
│       ├── spring/
│       │   ├── spring.xml     # Spring 核心配置
│       │   └── spring-mvc.xml# Spring MVC 配置
│       ├── mapper/           # MyBatis Mapper XML 文件
│       └── jdbc.properties    # 数据库连接配置
webapp/
├── WEB-INF/
│   └── views/                # JSP 视图文件
└── index.jsp
二、Spring 核心配置 (spring.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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><!-- 1. 加载数据库配置文件 --><context:property-placeholder location="classpath:jdbc.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}"/><!-- 连接池参数 --><property name="initialSize" value="5"/><property name="maxActive" value="20"/></bean><!-- 3. 配置 MyBatis 的 SqlSessionFactory --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 绑定数据源 --><property name="dataSource" ref="dataSource"/><!-- 指定 MyBatis Mapper XML 文件路径 --><property name="mapperLocations" value="classpath:mapper/*.xml"/><!-- 可选:MyBatis 全局配置文件 --><property name="configLocation" value="classpath:mybatis-config.xml"/></bean><!-- 4. 自动扫描 Mapper 接口 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="com.example.dao"/></bean><!-- 5. 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><property name="dataSource" ref="dataSource"/></bean><!-- 6. 开启注解驱动的事务管理 --><tx:annotation-driven transaction-manager="transactionManager"/><!-- 7. 扫描 Service 层 --><context:component-scan base-package="com.example.service"/>
</beans>
关键配置说明:
-  <context:property-placeholder>
 加载jdbc.properties文件中的数据库连接参数。
 •jdbc.driver: 数据库驱动类(如com.mysql.cj.jdbc.Driver)。
 •jdbc.url: 数据库连接 URL(如jdbc:mysql://localhost:3306/test)。
 •jdbc.username/jdbc.password: 数据库用户名和密码。
-  DruidDataSource
 • 使用 Druid 连接池管理数据库连接。
 •initialSize/maxActive: 连接池初始大小和最大连接数。
-  SqlSessionFactoryBean
 • 核心类,用于创建 MyBatis 的SqlSession。
 •mapperLocations: 指定 Mapper XML 文件的路径(支持通配符*)。
-  MapperScannerConfigurer
 • 自动扫描 DAO 层的 Mapper 接口,并注册为 Spring Bean。
 •basePackage: Mapper 接口所在的包路径。
-  DataSourceTransactionManager
 • 基于数据源的事务管理器,用于管理数据库事务。
 •<tx:annotation-driven>开启@Transactional注解支持。
三、Spring MVC 配置 (spring-mvc.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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsd"><!-- 1. 开启注解驱动(支持 @Controller、@RequestMapping 等) --><mvc:annotation-driven/><!-- 2. 静态资源处理(CSS/JS/图片) --><mvc:resources mapping="/static/**" location="/static/"/><!-- 3. 视图解析器(JSP) --><bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"/><property name="suffix" value=".jsp"/></bean><!-- 4. 扫描 Controller 层 --><context:component-scan base-package="com.example.controller"/>
</beans>
关键配置说明:
-  <mvc:annotation-driven>
 • 启用 Spring MVC 的注解驱动功能(如@Controller、@RequestMapping)。
 • 自动注册RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
-  <mvc:resources>
 • 处理静态资源请求(如/static/css/style.css)。
 •mapping: URL 映射规则。
 •location: 静态资源在项目中的路径。
-  InternalResourceViewResolver
 • 将逻辑视图名解析为具体的 JSP 文件路径。
 •prefix: 视图文件的前缀路径(如/WEB-INF/views/book/list.jsp)。
 •suffix: 视图文件的后缀(如.jsp)。
四、MyBatis 全局配置 (mybatis-config.xml,可选)
 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 1. 全局设置 --><settings><!-- 开启驼峰命名映射(数据库字段 user_name → Java 属性 userName) --><setting name="mapUnderscoreToCamelCase" value="true"/><!-- 开启缓存 --><setting name="cacheEnabled" value="true"/></settings><!-- 2. 实体类别名(简化 Mapper XML 中的类型书写) --><typeAliases><package name="com.example.entity"/></typeAliases>
</configuration>
关键配置说明:
-  mapUnderscoreToCamelCase
 • 自动将数据库字段的下划线命名转换为 Java 属性的驼峰命名。
-  typeAliases
 • 为实体类设置别名,例如<select resultType="Book">代替全类名com.example.entity.Book。
五、数据库连接配置 (jdbc.properties)
 
# MySQL 驱动
jdbc.driver=com.mysql.cj.jdbc.Driver
# 数据库连接 URL(注意时区设置)
jdbc.url=jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456
注意事项:
• serverTimezone=UTC: 解决 MySQL 8.0 时区问题。
 • useSSL=false: 禁用 SSL 连接(生产环境不建议)。
六、常见问题与解决
-  报错 NoSuchBeanDefinitionException
 • 原因: Spring 未扫描到 Service 或 Controller。
 • 解决: 检查<context:component-scan>的base-package路径。
-  静态资源无法加载 
 • 原因: 未配置<mvc:resources>或路径错误。
 • 解决: 确认静态资源目录与配置一致。
-  事务不生效 
 • 原因: 未开启<tx:annotation-driven>或方法非public。
 • 解决: 确保@Transactional注解在public方法上。
七、总结
• 最少配置项:
- 数据源 (dataSource)
- MyBatis 的 SqlSessionFactory
- Mapper 接口扫描 (MapperScannerConfigurer)
- 事务管理器 (DataSourceTransactionManager)
- Spring MVC 注解驱动 (<mvc:annotation-driven>)
- 视图解析器 (InternalResourceViewResolver)
• 扩展建议:
 • 添加拦截器 (HandlerInterceptor) 实现权限控制。
 • 使用 @RestController 开发 RESTful API。
 • 集成 Swagger 生成 API 文档。
12 Spring MVC 拦截器
一、拦截器的作用
拦截器(Interceptor)是 Spring MVC 提供的一种 请求预处理和后处理机制,允许在 控制器方法执行前后 和 请求完成后的回调阶段 插入自定义逻辑。常用于以下场景:
 • 权限验证(如登录检查)
 • 日志记录(记录请求参数、执行时间)
 • 性能监控(统计接口耗时)
 • 全局数据处理(如设置请求/响应编码)
二、拦截器 vs. 过滤器
| 特性 | 拦截器(Interceptor) | 过滤器(Filter) | 
|---|---|---|
| 依赖框架 | Spring MVC 提供 | Servlet 规范提供 | 
| 作用范围 | 仅拦截 Spring MVC 处理的请求 | 拦截所有请求(包括静态资源) | 
| 访问对象 | 可获取 Handler(控制器方法)、ModelAndView | 只能获取 Servlet API(Request/Response) | 
| 执行顺序 | 通过配置顺序控制 | 通过 @Order或web.xml配置顺序 | 
三、拦截器的核心方法
实现 HandlerInterceptor 接口,重写以下三个方法:
1. preHandle():在控制器方法执行前调用
 
• 返回值:
 • true:继续执行后续拦截器和控制器方法。
 • false:中断请求,直接返回响应。
 • 典型用途:权限校验、请求参数预处理。
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 示例:检查用户是否登录if (request.getSession().getAttribute("user") == null) {response.sendRedirect("/login");return false;}return true;
}
2. postHandle():在控制器方法执行后、视图渲染前调用
 
• 可修改 ModelAndView:调整返回的模型数据或视图。
 • 典型用途:向模型添加全局数据(如页面公共信息)。
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {if (modelAndView != null) {modelAndView.addObject("currentTime", System.currentTimeMillis());}
}
3. afterCompletion():在请求完成后调用(视图渲染完毕)
 
• 资源清理:关闭数据库连接、记录请求日志等。
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {// 示例:记录请求耗时long startTime = (Long) request.getAttribute("startTime");long cost = System.currentTimeMillis() - startTime;log.info("请求 {} 耗时 {}ms", request.getRequestURI(), cost);
}
四、配置拦截器
在 Spring MVC 配置文件(如 spring-mvc.xml)中注册拦截器,并指定拦截路径和排除路径。
1. 注册拦截器
<mvc:interceptors><!-- 全局拦截器(对所有请求生效) --><bean class="com.example.interceptor.LogInterceptor"/><!-- 自定义拦截器(指定路径) --><mvc:interceptor><mvc:mapping path="/admin/**"/>      <!-- 拦截路径 --><mvc:exclude-mapping path="/admin/login"/> <!-- 排除路径 --><bean class="com.example.interceptor.AuthInterceptor"/></mvc:interceptor>
</mvc:interceptors>
2. 路径匹配规则
• /**:匹配所有路径(包括子路径)。
 • /api/*:匹配一级路径(如 /api/user,不匹配 /api/user/1)。
 • /static/**:匹配静态资源路径。
五、示例:日志记录拦截器
public class LogInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {request.setAttribute("startTime", System.currentTimeMillis());log.info("请求开始: {} {}", request.getMethod(), request.getRequestURI());return true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {long startTime = (Long) request.getAttribute("startTime");long cost = System.currentTimeMillis() - startTime;log.info("请求结束: {} {} 耗时 {}ms", request.getMethod(), request.getRequestURI(), cost);}
}
六、多拦截器的执行顺序
若有多个拦截器,执行顺序为:
- preHandle():按配置顺序依次执行。
- postHandle():按配置的逆序执行。
- afterCompletion():按配置的逆序执行。
示例配置:
<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.example.interceptor.InterceptorA"/></mvc:interceptor><mvc:interceptor><mvc:mapping path="/**"/><bean class="com.example.interceptor.InterceptorB"/></mvc:interceptor>
</mvc:interceptors>
执行顺序:
- InterceptorA.preHandle() → InterceptorB.preHandle()
- InterceptorB.postHandle() → InterceptorA.postHandle()
- InterceptorB.afterCompletion() → InterceptorA.afterCompletion()
七、常见问题
1. 拦截器不生效
• 原因:未正确配置拦截路径或拦截器未被 Spring 管理。
 • 解决:检查 <mvc:mapping> 路径和包扫描配置。
2. 静态资源被拦截
• 原因:拦截路径配置为 /** 且未排除静态资源。
 • 解决:使用 <mvc:exclude-mapping> 排除静态资源路径。
3. 修改响应后流程中断
• 解决:在 preHandle() 中手动调用 response.getWriter().write() 并返回 false。
八、总结
• 核心作用:在请求生命周期的关键节点插入业务逻辑。
 • 适用场景:权限控制、日志记录、性能监控等。
 • 配置要点:路径匹配、执行顺序、排除规则。
13 文件上传和下载
一、文件上传
1. 添加依赖
在 pom.xml 中添加文件上传所需的依赖:
<!-- Apache Commons FileUpload -->
<dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.4</version>
</dependency>
2. 配置 Spring MVC 文件解析器
在 spring-mvc.xml 中配置 MultipartResolver:
<!-- 配置文件上传解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"><!-- 指定上传文件的最大大小(单位:字节) --><property name="maxUploadSize" value="10485760"/> <!-- 10MB --><!-- 指定默认编码 --><property name="defaultEncoding" value="UTF-8"/>
</bean>
3. 编写上传 Controller
@Controller
@RequestMapping("/file")
public class FileController {/*** 文件上传处理* @param file 前端传递的 MultipartFile 对象* @param model 返回消息模型* @return 上传结果页面*/@PostMapping("/upload")public String uploadFile(@RequestParam("file") MultipartFile file,Model model) {try {// 1. 检查文件是否为空if (file.isEmpty()) {model.addAttribute("msg", "上传文件不能为空!");return "result";}// 2. 获取原始文件名并处理路径问题String originalFilename = file.getOriginalFilename();// 防止文件名中包含路径,只保留文件名String fileName = new File(originalFilename).getName();// 3. 指定文件存储路径(示例中存储在项目的 uploads 目录下)String uploadDir = "uploads/";File dir = new File(uploadDir);if (!dir.exists()) {dir.mkdirs(); // 创建目录}// 4. 生成唯一文件名(避免重复)String savedFileName = UUID.randomUUID() + "_" + fileName;File dest = new File(dir, savedFileName);// 5. 保存文件到服务器file.transferTo(dest);model.addAttribute("msg", "文件上传成功!路径:" + dest.getAbsolutePath());} catch (IOException e) {model.addAttribute("msg", "文件上传失败:" + e.getMessage());}return "result";}
}
4. 前端上传表单(JSP)
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>文件上传</title>
</head>
<body><h2>文件上传</h2><!-- 必须指定 enctype="multipart/form-data" --><form action="/file/upload" method="post" enctype="multipart/form-data"><input type="file" name="file"><button type="submit">上传</button></form>
</body>
</html>
二、文件下载
1. 编写下载 Controller
@Controller
@RequestMapping("/file")
public class FileController {/*** 文件下载处理* @param filename 要下载的文件名* @return 文件流响应*/@GetMapping("/download")public ResponseEntity<byte[]> downloadFile(@RequestParam("filename") String filename) {try {// 1. 指定文件存储路径String uploadDir = "uploads/";File file = new File(uploadDir + filename);// 2. 检查文件是否存在if (!file.exists()) {return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);}// 3. 读取文件内容到字节数组byte[] fileBytes = Files.readAllBytes(file.toPath());// 4. 设置响应头HttpHeaders headers = new HttpHeaders();// 指定 Content-Disposition 告诉浏览器以下载方式处理headers.add("Content-Disposition", "attachment;filename=" + filename);// 设置 Content-Type(根据实际文件类型调整)headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);// 设置 Content-Length(可选)headers.setContentLength(fileBytes.length);// 5. 返回文件流return new ResponseEntity<>(fileBytes, headers, HttpStatus.OK);} catch (IOException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);}}
}
2. 前端下载链接(JSP)
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head><title>文件下载</title>
</head>
<body><h2>文件下载</h2><!-- 示例:下载名为 example.txt 的文件 --><a href="/file/download?filename=example.txt">下载文件</a>
</body>
</html>
三、关键注解与配置说明
-  @RequestParam("file")
 • 用于接收前端表单中name="file"的文件输入。
-  MultipartFile
 • Spring 提供的文件上传接口,提供transferTo()保存文件。
-  ResponseEntity<byte[]>
 • 封装 HTTP 响应的实体类,可直接返回字节数组和响应头。
-  HttpHeaders
 • 设置响应头,如Content-Disposition(告诉浏览器下载文件)。
四、常见问题与解决
-  上传文件大小限制 
 • 修改CommonsMultipartResolver的maxUploadSize属性。
-  中文文件名乱码 
 • 确保CommonsMultipartResolver的defaultEncoding设置为UTF-8。
-  文件存储路径权限问题 
 • 检查应用是否有权限写入目标目录。
-  安全建议 
 • 使用UUID重命名文件,避免文件名冲突和路径遍历攻击。
五、完整流程示意图
客户端 → 上传表单 → Spring MVC → MultipartResolver 解析 → Controller 保存文件
客户端 → 下载链接 → Controller 读取文件 → 返回字节流 → 浏览器下载
相关文章:
Spring MVC笔记
01 什么是Spring MVC Spring MVC 是 Spring 框架中的一个核心模块,专门用于构建 Web 应用程序。它基于经典的 MVC 设计模式(Model-View-Controller),但通过 Spring 的特性(如依赖注入、注解驱动)大幅简化了…...
 
BurpSuite插件jsEncrypter使用教程
一、前言 在当今Web应用安全测试中,前端加密已成为开发者保护敏感数据的常用手段。然而,这也给安全测试人员带来了挑战,传统的抓包方式难以获取明文数据,测试效率大打折扣。BurpSuite作为一款强大的Web安全测试工具,其…...
 
【C#实现手写Ollama服务交互,实现本地模型对话】
前言 C#手写Ollama服务交互,实现本地模型对话 最近使用C#调用OllamaSharpe库实现Ollama本地对话,然后思考着能否自己实现这个功能。经过一番查找,和查看OllamaSharpe源码发现确实可以。其实就是开启Ollama服务后,发送HTTP请求&a…...
Android Glide 框架线程管理模块原理的源码级别深入分析
一、引言 在现代的 Android 应用开发中,图片加载是一个常见且重要的功能。Glide 作为一款广泛使用的图片加载框架,以其高效、灵活和易用的特点受到了开发者的青睐。其中,线程管理模块是 Glide 框架中至关重要的一部分,它负责协调…...
每天记录一道Java面试题---day32
MySQL索引的数据结构、各自优劣 回答重点 B树:是一个平衡的多叉树,从根节点到每个叶子节点的高度差不超过1,而且同层级的节点间有指针相互连接。在B树上的常规检索,从根节点到叶子节点的搜索效率基本相当,不会出现大…...
 
Vue3 Pinia 符合直觉的Vue.js状态管理库
Pinia 符合直觉的Vue.js状态管理库 什么时候使用Pinia 当两个关系非常远的组件,要传递参数时使用Pinia组件的公共参数使用Pinia...
深度学习与大模型基础-向量
大家好!今天我们来聊聊向量(Vector)。别被这个词吓到,其实向量在我们的生活中无处不在,只是我们没注意罢了。 1. 向量是什么? 简单来说,向量就是有大小和方向的量。比如你从家走到学校&#x…...
【网络编程】完成端口 IOCP
10.11 完成端口 10.11.1 基本概念 完成端口的全称是I/O 完成端口,英文为IOCP(I/O Completion Port) 。IOCP是一个异 步I/O 的 API, 可以高效地将I/O 事件通知给应用程序。与使用select() 或是其他异步方法不同 的是,一个套接字与一个完成端口关联了起来…...
 
《苍穹外卖》SpringBoot后端开发项目重点知识整理(DAY1 to DAY3)
目录 一、在本地部署并启动Nginx服务1. 解压Nginx压缩包2. 启动Nginx服务3. 验证Nginx是否启动成功: 二、导入接口文档1. 黑马程序员提供的YApi平台2. YApi Pro平台3. 推荐工具:Apifox 三、Swagger1. 常用注解1.1 Api与ApiModel1.2 ApiModelProperty与Ap…...
管理网络安全
防火墙在 Linux 系统安全中有哪些重要的作用? 防火墙作为网络安全的第一道防线,能够根据预设的规则,对进出系统的网络流量进行严格筛选。它可以阻止未经授权的外部访问,只允许符合规则的流量进入系统,从而保护系统免受…...
 
明日直播|Go IoT 开发平台,开启万物智联新征程
在物联网技术飞速发展的当下,物联网行业却深受协议碎片化、生态封闭、开发低效等难题的困扰。企业和开发者们渴望找到一个能突破这些困境,实现高效、便捷开发的有力工具。 3 月 11 日(星期二)19:00,GitCode 特别邀请独…...
 
系统架构设计师—系统架构设计篇—软件架构风格
文章目录 概述经典体系结构风格数据流风格批处理管道过滤器对比 调用/返回风格主程序/子程序面向对象架构风格层次架构风格 独立构件风格进程通信事件驱动的系统 虚拟机风格解释器基于规则的系统 仓库风格(数据共享风格)数据库系统黑板系统超文本系统 闭…...
 
【MySQL_04】数据库基本操作(用户管理--配置文件--远程连接--数据库信息查看、创建、删除)
文章目录 一、MySQL 用户管理1.1 用户管理1.11 mysql.user表详解1.12 添加用户1.13 修改用户权限1.14 删除用户1.15 密码问题 二、MySQL 配置文件2.1 配置文件位置2.2 配置文件结构2.3 常用配置参数 三、MySQL远程连接四、数据库的查看、创建、删除4.1 查看数据库4.2 创建、删除…...
【Zinx】Day5-Part4:Zinx 的连接属性设置
目录 Day5-Part4:Zinx 的连接属性设置给连接添加连接配置的接口连接属性方法的实现 测试 Zinx-v1.0总结 Day5-Part4:Zinx 的连接属性设置 在 Zinx 当中,我们使用 Server 来开启服务并监听指定的端口,当接收到来自客户端的连接请求…...
 
【英伟达AI论文】多模态大型语言模型的高效长视频理解
摘要:近年来,基于视频的多模态大型语言模型(Video-LLMs)通过将视频处理为图像帧序列,显著提升了视频理解能力。然而,许多现有方法在视觉主干网络中独立处理各帧,缺乏显式的时序建模,…...
 
小程序事件系统 —— 32 事件系统 - 事件分类以及阻止事件冒泡
在微信小程序中,事件分为 冒泡事件 和 非冒泡事件 : 冒泡事件:当一个组件的事件被触发后,该事件会向父节点传递;(如果父节点中也绑定了一个事件,父节点事件也会被触发,也就是说子组…...
全球首款 5G-A 人形机器人发布
全球首款 5G-A 人形机器人于世界移动通信大会(MWC2025)上由中国移动、华为、乐聚联合发布。以下是关于这款机器人的详细介绍: 名称与背景 名称9:这款人形机器人名为 “夸父”,是中国移动、华为与乐聚机器人在 GTI 平台…...
Tomcat 新手入门指南
Tomcat 新手入门指南 Apache Tomcat 是一个开源的 Java Servlet 容器和 Web 服务器,广泛用于部署和运行 Java Web 应用程序。以下是 Tomcat 的入门指南,帮助你快速上手。 1. 安装 Tomcat 步骤 1: 下载 Tomcat 访问 Apache Tomcat 官网。选择适合的版…...
 
Flink-DataStreamAPI-生成水印
下面我们将学习Flink提供的用于处理事件时间戳和水印的API,也会介绍有关事件时间、流转时长和摄取时间,下面就让我们跟着官网来学习吧 一、水印策略介绍 为了处理事件时间,Flink需要知道事件时间戳,这意味着流中的每个元素都需要…...
 
【单片机】ARM 处理器简介
ARM 公司简介 ARM(Advanced RISC Machine) 是英国 ARM 公司(原 Acorn RISC Machine) 开发的一种精简指令集(RISC) 处理器架构。ARM 处理器因其低功耗、高性能、广泛适用性,成为嵌入式系统、移动…...
 
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
 
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
 
uniapp微信小程序视频实时流+pc端预览方案
方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度WebSocket图片帧定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐RTMP推流TRTC/即构SDK推流❌ 付费方案 (部分有免费额度&#x…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
 
Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
 
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
 
莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
 
Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...
 
FFmpeg:Windows系统小白安装及其使用
一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】,注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录(即exe所在文件夹)加入系统变量…...
 
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
