浪琴手表网站,网上做打字任务的网站,做网站会员推广哪个好,网站分布01 什么是Spring MVC
Spring MVC 是 Spring 框架中的一个核心模块#xff0c;专门用于构建 Web 应用程序。它基于经典的 MVC 设计模式#xff08;Model-View-Controller#xff09;#xff0c;但通过 Spring 的特性#xff08;如依赖注入、注解驱动#xff09;大幅简化了…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 核心依赖 --
dependencygroupIdorg.springframework/groupIdartifactIdspring-webmvc/artifactIdversion5.3.29/version
/dependency!-- Servlet API --
dependencygroupIdjavax.servlet/groupIdartifactIdjavax.servlet-api/artifactIdversion4.0.1/versionscopeprovided/scope
/dependency!-- JSP 支持 --
dependencygroupIdjavax.servlet.jsp/groupIdartifactIdjsp-api/artifactIdversion2.2/versionscopeprovided/scope
/dependency3. 配置 web.xml初始化 DispatcherServlet
web-app!-- 配置前端控制器 DispatcherServlet --servletservlet-namedispatcher/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-classinit-paramparam-namecontextConfigLocation/param-nameparam-value/WEB-INF/spring-mvc.xml/param-value/init-paramload-on-startup1/load-on-startup/servlet!-- 映射所有请求到 DispatcherServlet --servlet-mappingservlet-namedispatcher/servlet-nameurl-pattern//url-pattern/servlet-mapping
/web-app4. 创建 Spring MVC 配置文件/WEB-INF/spring-mvc.xml
!-- 开启注解驱动 --
mvc:annotation-driven/!-- 配置视图解析器JSP --
bean classorg.springframework.web.servlet.view.InternalResourceViewResolverproperty nameprefix value/WEB-INF/views//property namesuffix value.jsp/
/bean!-- 扫描 Controller 包 --
context:component-scan base-packagecom.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
bodyh1${message}/h1
/body
/html6. 部署到 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/ // 存放视图如HTMLstatic/ // 存放静态资源CSS/JS3. 编写 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:thhttp://www.thymeleaf.org
bodyh1 th:text${message}/h1
/body
/html5. 运行项目
• 直接运行 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/profileRequestMapping(/profile)public String profile() { ... }// 实际路径/user/listRequestMapping(/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必须不存在、paramvalue值匹配。
// 要求请求必须包含 id 参数
RequestMapping(params id)// 要求必须包含 id 且值为 100
RequestMapping(params id100)// 要求不能包含 debug 参数
RequestMapping(params !debug)(4) headers
• 过滤请求头要求请求头满足特定条件。 • 格式与 params 类似。
// 要求请求头包含 Content-Typeapplication/json
RequestMapping(headers Content-Typeapplication/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 的快捷组合注解
组合注解等效写法作用GetMappingRequestMapping(method RequestMethod.GET)处理 GET 请求PostMappingRequestMapping(method RequestMethod.POST)处理 POST 请求PutMappingRequestMapping(method RequestMethod.PUT)处理 PUT 请求DeleteMappingRequestMapping(method RequestMethod.DELETE)处理 DELETE 请求PatchMappingRequestMapping(method RequestMethod.PATCH)处理 PATCH 请求
示例
GetMapping(/user/{id}) // 等价于 RequestMapping(value/user/{id}, methodRequestMethod.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?id100GetMapping(value /detail, params id)public String detail(RequestParam Long id, Model model) {model.addAttribute(product, productService.findById(id));return product/detail;}// 匹配 POST 或 PUT /product/saveRequestMapping(value /save, method {RequestMethod.POST, RequestMethod.PUT})public String saveProduct(ModelAttribute Product product) {productService.save(product);return redirect:/product/list;}// 路径变量 正则匹配如 /product/category/electronicsGetMapping(/category/{type:[a-z]})public String listByCategory(PathVariable String type, Model model) {model.addAttribute(products, productService.findByCategory(type));return product/list;}
}05 Resful风格
RESTfulREpresentational State Transfer是一种基于 HTTP 协议的 API 设计风格强调以资源为中心通过统一的接口和标准方法GET/POST/PUT/DELETE 等操作资源。 一、RESTful 的核心原则 资源Resource • 所有数据或服务抽象为资源如用户、订单通过 URI统一资源标识符 唯一标识。 • 示例/users用户集合、/users/1001ID 为 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?id1001
✅ RESTful: GET /users/1001• 层级关系使用 / 分隔
GET /users/1001/orders # 获取用户 1001 的所有订单• 复数形式命名集合
GET /users # 用户集合
POST /users # 创建用户• 过滤、排序、分页通过查询参数实现
GET /users?page2size10sortname,asc # 分页排序
GET /users?nameJohnage30 # 过滤2. HTTP 方法使用规范
HTTP 方法操作类型幂等性示例GET查询资源是GET /users/1001POST创建资源否POST /usersPUT全量更新是PUT /users/1001PATCH部分更新否PATCH /users/1001DELETE删除资源是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 ResponseEntityUser 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 ResponseEntityUser 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 ResponseEntityErrorResponse 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 ListUser getAllUsers() {return userService.findAll();}// 创建用户PostMappingpublic ResponseEntityUser 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: aliceexample.com
}• 响应状态码 201
{id: 1001,name: Alice,email: aliceexample.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 仍为 /page1return 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 参数或表单字段默认必传可设 requiredfalse。
GetMapping(/user)
public String getUser(RequestParam(id) Long userId, RequestParam(value name, defaultValue Guest) String userName) {// URL: /user?id1001nameAlice// userId1001, userNameAlice若未传name默认为Guestreturn user/detail;
}• PathVariable获取 URL 路径变量。
GetMapping(/user/{id})
public String getUser(PathVariable(id) Long userId) {// URL: /user/1001 → userId1001return 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 ResponseEntityUser 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 生态中JSONJavaScript Object Notation 是主流的轻量级数据交换格式而 Jackson 是处理 JSON 序列化与反序列化的核心库。 一、JSON 简介
1. 什么是 JSON
• 轻量级数据格式以键值对key: value形式组织数据易读且兼容性强。 • 数据结构 • 对象{ key: value } • 数组[ value1, value2 ] • 值类型字符串、数字、布尔值、null、对象、数组。
2. 应用场景
• 前后端数据交互API 请求和响应。 • 配置文件如 package.json。 • NoSQL 数据库如 MongoDB存储格式。
3. 对比 XML
特性JSONXML可读性高结构简洁较低标签冗余数据体积更小更大解析速度更快较慢扩展性弱无命名空间、属性等概念强支持复杂结构 二、Jackson 核心功能
Jackson 是 Java 生态中最流行的 JSON 处理库提供以下能力
序列化将 Java 对象转换为 JSON 字符串。反序列化将 JSON 字符串解析为 Java 对象。数据绑定支持注解驱动配置。流式 API高性能处理大 JSON 数据。 三、Spring 中集成 Jackson
Spring MVC 默认通过 MappingJackson2HttpMessageConverter 集成 Jackson自动处理 JSON 转换。
1. 添加依赖
!-- Maven 依赖 --
dependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactIdversion2.15.2/version
/dependency2. 启用 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 GMT8)private LocalDateTime createTime;
}
// 序列化为 2023-10-01 14:30:003. 空值处理
• 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 对比
特性FastjsonJackson性能更高尤其序列化较高安全性历史漏洞较多需使用最新版本安全性较好API 简洁性极简静态方法稍复杂需 ObjectMapper 实例社区生态国内流行文档丰富国际主流生态更成熟维护状态阿里巴巴维护更新频繁长期稳定更新 三、Spring 中集成 Fastjson
Spring Boot 默认使用 Jackson若需替换为 Fastjson需手动配置消息转换器。
1. 添加依赖
!-- Maven 依赖 --
dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion2.0.34/version !-- 使用最新版本避免安全漏洞 --
/dependency2. 配置 Fastjson 消息转换器
Configuration
public class WebConfig implements WebMvcConfigurer {Overridepublic void configureMessageConverters(ListHttpMessageConverter? 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);// 处理中文乱码ListMediaType 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\}];
ListUser 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.javaPOJO层
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 {ListBook selectAll();int insert(Book book);int deleteById(Integer id);
}4. MyBatis Mapper XML BookMapper.xml
?xml version1.0 encodingUTF-8?
!DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd
mapper namespacecom.example.dao.BookMapperselect idselectAll resultTypeBookSELECT id, name, author, price FROM book/selectinsert idinsert parameterTypeBookINSERT INTO book(name, author, price)VALUES(#{name}, #{author}, #{price})/insertdelete iddeleteById parameterTypeIntegerDELETE FROM book WHERE id #{id}/delete
/mapper5. Service层实现业务逻辑
// 接口 BookService.java
package com.example.service;
import com.example.entity.Book;
import java.util.List;public interface BookService {ListBook 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 ListBook listBooks() {return bookMapper.selectAll();}OverrideTransactionalpublic void addBook(Book book) {bookMapper.insert(book);}OverrideTransactionalpublic 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.drivercom.mysql.cj.jdbc.Driver
jdbc.urljdbc:mysql://localhost:3306/book_db?useSSLfalseserverTimezoneUTC
jdbc.usernameroot
jdbc.password123456(2) spring.xmlSpring核心配置
!-- 数据源 --
bean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName value${jdbc.driver}/property nameurl value${jdbc.url}/property nameusername value${jdbc.username}/property namepassword value${jdbc.password}/
/bean!-- MyBatis SqlSessionFactory --
bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBeanproperty namedataSource refdataSource/property namemapperLocations valueclasspath:mapper/*.xml/
/bean!-- Mapper接口扫描 --
bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namebasePackage valuecom.example.dao/
/bean!-- 事务管理器 --
bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource/
/bean!-- 开启注解扫描 --
context:component-scan base-packagecom.example.service/(3) spring-mvc.xmlSpring MVC配置
!-- 注解驱动 --
mvc:annotation-driven/!-- 视图解析器 --
bean classorg.springframework.web.servlet.view.InternalResourceViewResolverproperty nameprefix value/WEB-INF/views//property namesuffix value.jsp/
/bean!-- 扫描控制器 --
context:component-scan base-packagecom.example.controller/!-- 静态资源处理 --
mvc:resources mapping/static/** location/static//8. 视图层 list.jsp
% page contentTypetext/html;charsetUTF-8 %
% taglib prefixc urihttp://java.sun.com/jsp/jstl/core %
html
headtitle图书列表/title
/head
bodyh2图书列表/h2table border1trthID/thth书名/thth作者/thth价格/thth操作/th/trc:forEach items${books} varbooktrtd${book.id}/tdtd${book.name}/tdtd${book.author}/tdtd${book.price}/tdtda href/book/delete/${book.id}删除/a/td/tr/c:forEach/tableh3添加新书/h3form action/book/add methodpost书名input typetext namenamebr作者input typetext nameauthorbr价格input typenumber step0.01 namepricebrbutton typesubmit提交/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 和 MyBatisSSM时 必须配置的核心内容分步骤说明每个配置文件的作用和关键配置项。 一、项目结构
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 version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:txhttp://www.springframework.org/schema/txxsi:schemaLocationhttp://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 locationclasspath:jdbc.properties/!-- 2. 配置数据源Druid --bean iddataSource classcom.alibaba.druid.pool.DruidDataSourceproperty namedriverClassName value${jdbc.driver}/property nameurl value${jdbc.url}/property nameusername value${jdbc.username}/property namepassword value${jdbc.password}/!-- 连接池参数 --property nameinitialSize value5/property namemaxActive value20//bean!-- 3. 配置 MyBatis 的 SqlSessionFactory --bean idsqlSessionFactory classorg.mybatis.spring.SqlSessionFactoryBean!-- 绑定数据源 --property namedataSource refdataSource/!-- 指定 MyBatis Mapper XML 文件路径 --property namemapperLocations valueclasspath:mapper/*.xml/!-- 可选MyBatis 全局配置文件 --property nameconfigLocation valueclasspath:mybatis-config.xml//bean!-- 4. 自动扫描 Mapper 接口 --bean classorg.mybatis.spring.mapper.MapperScannerConfigurerproperty namebasePackage valuecom.example.dao//bean!-- 5. 事务管理器 --bean idtransactionManager classorg.springframework.jdbc.datasource.DataSourceTransactionManagerproperty namedataSource refdataSource//bean!-- 6. 开启注解驱动的事务管理 --tx:annotation-driven transaction-managertransactionManager/!-- 7. 扫描 Service 层 --context:component-scan base-packagecom.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 version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:mvchttp://www.springframework.org/schema/mvcxsi:schemaLocationhttp://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 classorg.springframework.web.servlet.view.InternalResourceViewResolverproperty nameprefix value/WEB-INF/views//property namesuffix value.jsp//bean!-- 4. 扫描 Controller 层 --context:component-scan base-packagecom.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 version1.0 encodingUTF-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 namemapUnderscoreToCamelCase valuetrue/!-- 开启缓存 --setting namecacheEnabled valuetrue//settings!-- 2. 实体类别名简化 Mapper XML 中的类型书写 --typeAliasespackage namecom.example.entity//typeAliases
/configuration关键配置说明: mapUnderscoreToCamelCase • 自动将数据库字段的下划线命名转换为 Java 属性的驼峰命名。 typeAliases • 为实体类设置别名例如 select resultTypeBook 代替全类名 com.example.entity.Book。 五、数据库连接配置 (jdbc.properties)
# MySQL 驱动
jdbc.drivercom.mysql.cj.jdbc.Driver
# 数据库连接 URL注意时区设置
jdbc.urljdbc:mysql://localhost:3306/test?useSSLfalseserverTimezoneUTC
jdbc.usernameroot
jdbc.password123456注意事项:
• serverTimezoneUTC: 解决 MySQL 8.0 时区问题。 • useSSLfalse: 禁用 SSL 连接生产环境不建议。 六、常见问题与解决 报错 NoSuchBeanDefinitionException • 原因: Spring 未扫描到 Service 或 Controller。 • 解决: 检查 context:component-scan 的 base-package 路径。 静态资源无法加载 • 原因: 未配置 mvc:resources 或路径错误。 • 解决: 确认静态资源目录与配置一致。 事务不生效 • 原因: 未开启 tx:annotation-driven 或方法非 public。 • 解决: 确保 Transactional 注解在 public 方法上。 七、总结
• 最少配置项:
数据源 (dataSource)MyBatis 的 SqlSessionFactoryMapper 接口扫描 (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 APIRequest/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 classcom.example.interceptor.LogInterceptor/!-- 自定义拦截器指定路径 --mvc:interceptormvc:mapping path/admin/**/ !-- 拦截路径 --mvc:exclude-mapping path/admin/login/ !-- 排除路径 --bean classcom.example.interceptor.AuthInterceptor//mvc:interceptor
/mvc:interceptors2. 路径匹配规则
• /**匹配所有路径包括子路径。 • /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:interceptorsmvc:interceptormvc:mapping path/**/bean classcom.example.interceptor.InterceptorA//mvc:interceptormvc:interceptormvc:mapping path/**/bean classcom.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 --
dependencygroupIdcommons-fileupload/groupIdartifactIdcommons-fileupload/artifactIdversion1.4/version
/dependency2. 配置 Spring MVC 文件解析器
在 spring-mvc.xml 中配置 MultipartResolver
!-- 配置文件上传解析器 --
bean idmultipartResolver classorg.springframework.web.multipart.commons.CommonsMultipartResolver!-- 指定上传文件的最大大小单位字节 --property namemaxUploadSize value10485760/ !-- 10MB --!-- 指定默认编码 --property namedefaultEncoding valueUTF-8/
/bean3. 编写上传 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 contentTypetext/html;charsetUTF-8 %
html
headtitle文件上传/title
/head
bodyh2文件上传/h2!-- 必须指定 enctypemultipart/form-data --form action/file/upload methodpost enctypemultipart/form-datainput typefile namefilebutton typesubmit上传/button/form
/body
/html二、文件下载
1. 编写下载 Controller
Controller
RequestMapping(/file)
public class FileController {/*** 文件下载处理* param filename 要下载的文件名* return 文件流响应*/GetMapping(/download)public ResponseEntitybyte[] 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 contentTypetext/html;charsetUTF-8 %
html
headtitle文件下载/title
/head
bodyh2文件下载/h2!-- 示例下载名为 example.txt 的文件 --a href/file/download?filenameexample.txt下载文件/a
/body
/html三、关键注解与配置说明 RequestParam(file) • 用于接收前端表单中 namefile 的文件输入。 MultipartFile • Spring 提供的文件上传接口提供 transferTo() 保存文件。 ResponseEntitybyte[] • 封装 HTTP 响应的实体类可直接返回字节数组和响应头。 HttpHeaders • 设置响应头如 Content-Disposition告诉浏览器下载文件。 四、常见问题与解决 上传文件大小限制 • 修改 CommonsMultipartResolver 的 maxUploadSize 属性。 中文文件名乱码 • 确保 CommonsMultipartResolver 的 defaultEncoding 设置为 UTF-8。 文件存储路径权限问题 • 检查应用是否有权限写入目标目录。 安全建议 • 使用 UUID 重命名文件避免文件名冲突和路径遍历攻击。 五、完整流程示意图
客户端 → 上传表单 → Spring MVC → MultipartResolver 解析 → Controller 保存文件
客户端 → 下载链接 → Controller 读取文件 → 返回字节流 → 浏览器下载