SpringMVC异常处理器
1 如何处理异常
- 编程式异常处理:将异常处理代码与核心业务代码书写在同一代码块中,耦合度高(不推荐)
- 声明式异常处理:将异常处理代码,先横向提取到切面类中,再动态织入到核心业务代码(推荐使用)
2 声明式异常处理
声明式异常处理是 Spring MVC 中一种强大且灵活的技术,它允许开发者通过注解和配置轻松地定义异常处理规则,而无需在业务逻辑中嵌入复杂的 try-catch 结构。SpringMVC提供很多注解实现异常处理器,其中常用注解如下:
@ControllerAdvice注解用于定义一个类作为全局异常处理器,它可以应用于整个应用程序中的所有控制器。
@ExceptionHandler注解,可以在该类中定义方法来处理特定类型的异常。
2.1 全局异常处理
这是最常用的一种声明式异常处理方法,它允许你定义一个或多个类来集中处理所有控制器抛出的异常。
package com.mytest.myexceptionhandler;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//@ResponseBody
//@ControllerAdvice //定义异常处理器
//@RestControllerAdvice // = @ControllerAdvice+@ResponseBody
@ControllerAdvice
public class MyExceptionHandler {
//处理空指针异常
@ResponseBody
@ExceptionHandler(NullPointerException.class)
public String doNullPointerException(Exception ex) {
System.out.println("ex = " + ex);
return "{'status:'501'}"; //响应文本提示:错误信息
}
//处理算术异常
@ExceptionHandler(ArithmeticException.class)
public String doArithmeticException(Exception ex) {
System.out.println("ex = " + ex);
return "/error/error_502.html"; //响应页面提示:错误信息
}
}
2.2 局部异常处理(了解)
除了全局异常处理器外,你还可以在每个控制器内部使用
@ExceptionHandler来处理特定于该控制器的异常。这种方式提供了更细粒度的控制,但不如全局处理器灵活。
@Controller
public class MyController {
@ExceptionHandler(ResourceNotFoundException.class)
public String handleResourceNotFoundException(ResourceNotFoundException ex, Model model) {
model.addAttribute("errorMessage", ex.getMessage());
return "error/resource-not-found"; // 返回视图名称
}
// 控制器其他方法...
}
SpringMVC拦截器
过滤器与拦截器相同与不同
- 相似点
- 拦截:必须先把请求拦住,才能执行后续操作
- 过滤:拦截器或过滤器存在的意义就是对请求进行统一处理
- 放行:对请求执行了必要操作后,放请求过去,让它访问原本想要访问的资源
- 不同点
- 工作平台不同
- 过滤器工作在 Servlet 容器中
- 拦截器工作在 SpringMVC 的基础上
- 拦截的范围
- 过滤器:能够拦截到的最大范围是整个 Web 应用
- 拦截器:能够拦截到的最大范围是整个 SpringMVC 负责的请求
- IOC 容器支持
- 过滤器:想得到 IOC 容器需要调用专门的工具方法,是间接的
- 拦截器:它自己就在 IOC 容器中,所以可以直接从 IOC 容器中装配组件,也就是可以直接得到 IOC 容器的支持
- 工作平台不同
1 拦截器(Interceptor)简介
在 Spring MVC 中,
Interceptor(拦截器)是一种用于在请求处理的不同阶段插入自定义逻辑的机制。拦截器可以用来实现诸如日志记录、权限检查、性能监控、国际化设置等功能,而无需修改业务逻辑代码。下面是对Interceptor的详细解析:拦截器允许开发者在以下三个关键点上执行额外的逻辑:
- 预处理请求(Pre-Handling)
- 在请求被传递给控制器之前执行。
- 可以用于验证用户身份、解析请求参数、设置线程局部变量等。
- 后处理响应(Post-Handling)
- 在控制器方法执行完毕但视图渲染之前执行。
- 可以用于添加额外的数据到模型中,或者修改返回的
ModelAndView对象。- 完成处理(After Completion)
- 在整个请求处理完成后执行,无论是否发生异常。
- 通常用于资源清理、记录日志等。
2 拦截器基本实现
2.1 定义拦截器
package com.mytest.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Component("myInterceptor1")
public class MyInterceptor1 implements HandlerInterceptor {
//在执行Controller之前执行
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("==>1.Myinterceprot111->preHandle()!!!");
return true; //true:放行 false:不放行
}
//在执行Controller之后执行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("==>3.Myinterceprot111->postHandle()!!!");
}
//在最后执行
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("==>4.Myinterceprot111->afterCompletion()!!!");
}
}
2.2 注册拦截器
package com.mytest.config;
import com.mytest.interceptor.MyInterceptor1;
import com.mytest.interceptor.MyInterceptor2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SpringMVCConfig implements WebMvcConfigurer {
@Autowired
private MyInterceptor1 myInterceptor1;
//注册拦截器
public void addInterceptors(InterceptorRegistry registry) {
//注册拦截器(myInterceptor1)
registry.addInterceptor(myInterceptor1).addPathPatterns("/interceptorController/testInterceptor");
}
}
3 拦截器工作原理
3.1 单个拦截器工作原理
- 客户端向服务器发送请求
- 执行拦截器第一个方法preHandle(),放行请求(return true)
- 执行Controller中相应方法
- 执行拦截器第二个方法postHandle()
- 执行拦截器第三个方法afterCompletion()
3.2 多个拦截器工作原理
假设我们有三个拦截器 A、B 和 C,并且它们按此顺序被添加到拦截器链中。那么,在处理请求的过程中,各个拦截器的方法将按照以下顺序执行:
Pre-Handle 阶段
- A.preHandle()
- B.preHandle()
- C.preHandle()
在这个阶段,拦截器的
preHandle()方法会按照它们被注册的顺序依次调用。每个拦截器都有机会决定是否继续处理请求。如果任何一个拦截器的preHandle()返回false,则整个请求处理过程将会终止,后续的拦截器和控制器方法都不会被执行。
- Controller 处理
如果所有拦截器的
preHandle()方法都返回true,请求将继续传递给控制器进行处理。控制器执行完毕后,会生成一个ModelAndView对象(或类似的响应结果)。
Post-Handle 阶段
- C.postHandle()
- B.postHandle()
- A.postHandle()
一旦控制器完成了业务逻辑处理,但视图还未渲染之前,拦截器链中的
postHandle()方法将以逆序执行。也就是说,最后一个注册的拦截器 C 的postHandle()方法最先被调用,然后是 B 和 A。这个阶段可以用来修改ModelAndView或者添加额外的数据。
After-Completion 阶段
- C.afterCompletion()
- B.afterCompletion()
- A.afterCompletion()
最后,在整个请求处理完成后(包括视图渲染),无论是否发生异常,拦截器链中的
afterCompletion()方法也会以逆序执行。这一步骤通常用于清理资源、记录日志等操作。总结:假设这三个拦截器按 A -> B -> C 的顺序注册,当一个请求到达时,控制台输出如下:
A - Pre Handle B - Pre Handle C - Pre Handle // Controller 执行... C - Post Handle B - Post Handle A - Post Handle // 视图渲染完成... C - After Completion B - After Completion A - After Completion注意事项
- 短路行为:如果某个拦截器的
preHandle()方法返回false,则该请求将不会继续传递给下一个拦截器或控制器,而是直接进入afterCompletion()阶段。- 异常处理:如果在
preHandle()或控制器执行期间抛出了异常,postHandle()不会被调用,但是afterCompletion()仍然会被调用,并且异常信息会作为参数传递给它。- 线程安全性:确保拦截器中的共享资源是线程安全的,尤其是在多线程环境下使用时。
3.3 源码解析拦截器工作原理
- SpringMVC断点入口
- preHandle()正序执行
- postHandle()倒序执行
- afterCompletion()倒序执行
4 拦截器与过滤器异同
| 特性 | 拦截器(Interceptor) | 过滤器(Filter) |
|---|---|---|
| 作用范围 | 仅限于 Spring MVC 控制器请求,不处理静态资源或其他非 Spring MVC 请求。 | 可应用于整个 Web 应用程序中的所有请求/响应,包括静态资源。 |
| 生命周期 | 生命周期依赖于 Spring 容器,在应用启动时被创建并注册到 Spring MVC 配置中。 | 在整个应用程序的生命周期中始终存在,随应用启动而初始化。 |
| 配置方式 | 通过 Java 配置类(实现 WebMvcConfigurer 接口)或 XML 配置文件来定义。 | 通过 web.xml 文件或者使用注解(如 @WebFilter 和 ServletContainerInitializer)来定义。 |
| 执行顺序 | 在请求已经被 DispatcherServlet 接收后但在传递给具体处理器之前执行;preHandle() 按注册顺序,postHandle() 和 afterCompletion() 逆序。 | 在请求到达 Spring MVC 的 DispatcherServlet 之前执行;过滤器链按配置顺序依次执行。 |
| 功能特性 | 提供了更细粒度的控制,可以在请求处理的不同阶段插入自定义逻辑,如认证授权、性能监控等。 | 支持字符编码设置、日志记录、权限检查等功能,可以直接操作 HttpServletRequest 和 HttpServletResponse 对象。 |
| 性能考虑 | 由于只针对 Spring MVC 请求,可能具有更好的性能表现,因为它减少了不必要的处理步骤。 | 因为会拦截所有请求,处理大量请求时可能会引入额外开销,特别是对静态资源的处理。 |
| 适用场景 | 适合处理由 Spring MVC 控制器管理的请求,并利用框架提供的丰富特性。 | 适合需要对所有 HTTP 请求(包括静态资源)进行统一处理的情况。 |
SpringMVC数据校验
1 SpringMVC数据校验概念
Spring MVC 提供了强大的数据校验功能,以确保从客户端接收到的数据符合预期的格式和规则。通过使用 Bean Validation API(如 Hibernate Validator),你可以轻松地为输入数据添加校验逻辑,并在控制器层中处理验证结果。
- 常用校验规则如下:
校验注解 作用 @AssertFalse 验证Boolean类型字段是否为false @AssertTrue 验证Boolean类型字段是否为true @DecimalMax 验证字符串表示的数字是否小于等于指定的最大值 @DecimalMin 验证字符串表示的数字是否大于等于指定的最小值 @Digits(integer, fraction) 验证数值是否符合指定的格式,integer指定整数精度,fraction指定小数精度 验证字符串是否为邮箱地址格式 @Future 验证日期是否在当前时间之后 @Past 验证日期是否在当前时间之前 @Min(value) 验证数字是否大于等于指定的最小值 @Max(value) 验证数字是否小于等于指定的最大值 @Null 验证对象是否为null @NotNull 验证对象是否不为null, 与@Null相反**(a!=null)** @NotEmpty 验证字符串是否非空**(a!=null && a!=“”)** @NotBlank 验证字符串是否非空白字符**(a!=null && a.trim().length > 0)** @Size(max=, min=) 验证字符串、集合、Map、数组的大小是否在指定范围内 @Pattern(regexp=, flag=) 验证字符串是否符合指定的正则表达式
2 SpringMVC数据校验基本实现
2.1 导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.2 定义校验规则
在 DTO(Data Transfer Object)或实体类上使用注解来定义校验规则。这些注解可以应用于字段、getter 方法或类级别。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentDTO {
@NotNull(message = "id不能为空!!!")
private Integer stuId;
@Length(min = 3, max = 6, message = "长度在3-6之间!!!")
private String stuName;
@Min(value = 18, message = "年龄最小18岁!!!")
@Max(value = 120,message = "年龄最大120岁!!!")
private Integer stuAge;
@Email(message = "邮箱格式不正确!!!")
private String stuEmail;
}
7.2.3 控制器中验证
package com.mytest.controller;
import com.mytest.pojo.Student;
import com.mytest.pojo.vo.StudentVO;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class TestValidateController {
@GetMapping("/testValidate")
public String doValidate(@RequestBody @Valid StudentDTO studentDTO,
BindingResult br) {
if(br.hasErrors()){
Map<String,Object> errorMap = new HashMap<>();
List<FieldError> fieldErrors = br.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return errorMap.toString();
}
Student student = new Student();
BeanUtils.copyProperties(studentDTO, student);
System.out.println("student = " + student);
return "doValidate";
}
}
3 SpringMVC自定义数据校验器(了解)
3.1 定义校验注解
package com.mytest.annotation;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(
validatedBy = {GenderValidate.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Gender {
String message() default "性别只能是男或女!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
7.3.2 定义校验注解规则
package com.mytest.annotation;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
public class GenderValidate implements ConstraintValidator<Gender,String> {
@Override
public void initialize(Gender constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return value.equals("男") || value.equals("女");
}
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StudentDTO {
@NotNull(message = "id不能为空!!!")
private Integer stuId;
@Length(min = 3, max = 6, message = "长度在3-6之间!!!")
private String stuName;
@Min(value = 18, message = "年龄最小18岁!!!")
@Max(value = 120,message = "年龄最大120岁!!!")
private Integer stuAge;
@Email(message = "邮箱格式不正确!!!")
private String stuEmail;
//自定义验证器
@Gender(message = "请求输入正确的性别!")
private String stuGender;
}
4 VO与DTO
4.1 各种O的概念
在 Spring MVC 中,
VO(Value Object)、DTO(Data Transfer Object)等对象类型用于不同场景下的数据处理和传输。理解这些概念及其用途对于设计良好的分层架构非常重要。以下是关于各种O介绍:
- Value Object (VO):强调不可变性和基于内容的相等性,适用于表示具体值或属性组合。
- Data Transfer Object (DTO):用于简化不同层次间的数据传输,避免直接暴露实体类。
- Entity:表示持久化的业务实体,通常与数据库表相对应。
- Form Object:专为表单提交设计,便于收集和验证用户输入。
- Command Object:封装了执行某项操作所需的所有信息,常用于命令模式。
- Transfer Object (TO):专注于远程调用或跨进程通信中的高效数据传输。
4.2 DTO介绍
DTO全称:Data Transfer Object (DTO)
定义
DTO 主要用于在不同的应用程序层之间传递数据,特别是从服务层到表现层(如控制器)。它通常是一个简单的 POJO(Plain Old Java Object),包含一组 getter 和 setter 方法。
使用场景
- 简化复杂业务逻辑与视图之间的数据交换。
- 避免直接暴露实体类给前端,从而保护内部数据结构并减少耦合。
- 支持多样的展示需求,例如将多个实体的信息整合到一个 DTO 中进行返回。
案例代码
@Data @NoArgsConstructor @AllArgsConstructor public class StudentDTO { @NotNull(message = "id不能为空!!!") private Integer stuId; @Length(min = 3, max = 6, message = "长度在3-6之间!!!") private String stuName; @Min(value = 18, message = "年龄最小18岁!!!") @Max(value = 120,message = "年龄最大120岁!!!") private Integer stuAge; @Email(message = "邮箱格式不正确!!!") private String stuEmail; //自定义验证器 @Gender(message = "请求输入正确的性别!") private String stuGender; }
4.3 VO介绍(了解)
VO全称:Value Object
不可变性:Value Object 是一个表示值的对象,它的状态是不可改变的。一旦创建,其属性就不能被修改。
相等性基于内容:两个 Value Object 如果它们的内容相同,则认为它们相等,而不是根据对象的引用地址。
使用场景
- 当你需要确保某个对象的状态不会发生变化时,比如货币、日期时间等。
- 在领域驱动设计(DDD)中,Value Object 用来封装具有特定含义的值或属性组合。
案例代码
public final class Money implements ValueObject { private final BigDecimal amount; private final Currency currency; public Money(BigDecimal amount, Currency currency) { this.amount = amount; this.currency = currency; } // Getters but no setters... }
Swagger接口文档
1 Swagger介绍
Swagger 是一个用于设计、构建、记录和使用 RESTful Web 服务的开源框架。它不仅简化了 API 的开发过程,还提供了强大的工具来生成交互式的 API 文档,使得开发者和消费者能够更好地理解和使用这些 API。
Swagger 可以快速生成实时接口文档,方便前后开发人员进行协调沟通。遵循 OpenAPI 规范。 Knife4j 是基于 Swagger之上的增强套件
什么是 Swagger?
Swagger 实际上是 OpenAPI 规范的一部分,OpenAPI 规范定义了一套规则来描述 RESTful API。而 Swagger 则提供了一系列工具和服务来支持这一规范,包括但不限于:
- Swagger Editor:一个基于浏览器的编辑器,允许你以 YAML 或 JSON 格式编写 OpenAPI 规范文件,并实时预览文档。
- Swagger UI:一个动态生成的 HTML 页面,根据 OpenAPI 规范文件展示 API 的详细信息,并允许用户直接在浏览器中测试 API 调用。
- Swagger Codegen:可以从 OpenAPI 规范自动生成客户端 SDK 和服务器存根代码。
2 Swagger基本应用
2.1 常用API
Knife4j 使用,参考:doc.xiaominfo.com/docs/quick-…
swagger标准常用注解;
访问 http://ip:port/doc.html 即可查看接口文档
| 注解 | 标注位置 | 作用 |
|---|---|---|
| @Tag | controller 类 | 描述 controller 作用 |
| @Parameter | 参数 | 标识参数作用 |
| @Parameters | 参数 | 参数多重说明 |
| @Schema | model 层的 JavaBean | 描述模型作用及每个属性 |
| @Operation | 方法 | 描述方法作用 |
| @ApiResponse | 方法 | 描述响应状态码等 |
2.2 实现步骤
-
导入依赖
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId> <version>4.4.0</version> </dependency> -
编写配置文件:application.properties或application.yml
# springdoc-openapi项目配置 springdoc: swagger-ui: path: /swagger-ui.html tags-sorter: alpha operations-sorter: alpha api-docs: path: /v3/api-docs group-configs: - group: 'default' paths-to-match: '/**' packages-to-scan: com.mytest.controller # knife4j的增强配置,不需要增强可以不配 knife4j: enable: true setting: language: zh_cn -
使用注解
package com.mytest.pojo; import com.mytest.springmvc05restful.validation.annotations.Gender; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.*; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.web.bind.annotation.PathVariable; import java.io.Serializable; import java.math.BigDecimal; @AllArgsConstructor @NoArgsConstructor @Data // 单一职责原则 public class Employee implements Serializable { @Schema(description = "修改员工信息时,该属性必须有值.增加员工信息时则不需要赋值") private Integer id; @Schema(description = "员工姓名") private String name; private Integer age; private String email; private String address; private BigDecimal salary; private String gender; }import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; @RestController @RequestMapping("/api/v1") @Tag(name = "员工管理", description = "员工信息管理的控制器") public class UserController { @Operation(summary = "查询全部员工信息的处理器") @GetMapping("/employees") public String getEmployees() { List<Employee> employees =employeeService.findAllEmployee(); return employees.toString(); } @Operation(summary = "根据id修改员工信息的业务接口实现") @PutMapping("/employee") public String updateEmployee(@RequestBody Employee employee){ employeeService.updateEmnployee(employee); return "success"; } @Operation(summary = "添加员工信息的处理器") @Parameters({ @Parameter(name = "eid", description = "员工ID",in = ParameterIn.PATH), @Parameter(name = "salary", description = "员工薪资",in = ParameterIn.PATH), @Parameter(name = "gender", description = "员工性别",in = ParameterIn.PATH), @Parameter(name = "address", description = "员工住址") }) @PostMapping("/emp") public String insertEmployee(@RequestBody Employee employee) { employeeService.insertEmployee(employee); return "{'status':'ok'}"; } } -
访问Swagger UI
- 最后,访问Knife4j的文档地址:
http://ip:port/doc.html即可查看文档
- 最后,访问Knife4j的文档地址:
SpringMVC工作原理
1 SpringMVC九大组件
1.1 DispatcherServlet
- 作用:
- 前端控制器,是整个 Spring MVC 的控制中心。用户请求到达前端控制器后,由前端控制器分发请求至后端控制器。
- DispatchServlet中核心调度方法:doDispatch()
- 配置:通常在 web.xml 中配置 DispatcherServlet。
1.2 HandlerMapping
- 作用:
- 处理器映射器,负责根据用户请求找到 Handler(处理器),即 Controller。
- 通过HandlerMapping获取HandlerAdapter对象
- 类型:包括 BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping、RequestMappingHandlerMapping 等。
1.3 HandlerAdapter
- 作用:
- 处理器适配器,按照特定规则(HandlerAdapter 要求的规则)去执行 Handler。
- 通过HandlerAdapter调用Controller中相应方法
- 类型:包括 SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter、AnnotationMethodHandlerAdapter 等。
1.4 Handler(Controller)
- 作用:处理器,是后端控制器,在 MVC 模型中负责处理具体的业务逻辑。
- 注解:通常使用
@Controller注解标记一个类为 Controller。
1.5 ModelAndView
- 作用:封装了 Model 和 View 的信息。Controller 处理完用户请求后返回一个 ModelAndView 对象,其中包含了模型数据和视图信息。
- 结构:包含一个 Map 对象(用于存放模型数据)和一个 View 或视图名称(用于指定视图)。
1.6 ViewResolver
- 作用:视图解析器,根据逻辑视图名解析成真正的视图 View(如 JSP、Thymeleaf 等)。
- 类型:包括 InternalResourceViewResolver、FreeMarkerViewResolver、ThymeleafViewResolver 等。
1.7 View
- 作用:视图,负责将结果显示给用户。视图可以是 JSP、HTML、PDF 等任何形式的页面。
- 实现:通常由 ViewResolver 解析得到。
1.8 ExceptionHandler
- 作用:异常处理器,用于处理 Controller 中抛出的异常。
- 注解:使用
@ExceptionHandler注解标记一个方法为异常处理器。
1.9 Interceptor
- 作用:拦截器,类似于 Servlet 中的 Filter,用于在请求到达 Controller 之前或之后执行一些预处理或后处理操作。
- 配置:在 Spring MVC 配置文件中配置拦截器链。
2 SpringMVC工作原理
2.1 图解SpringMVC工作原理
2.2 SpringMVC工作原理源码简述
客户端发送请求:用户通过浏览器或其他客户端工具向服务器发起 HTTP 请求。
DispatcherServlet 接收请求:所有进入应用程序的请求首先由 DispatcherServlet 接收。
查找 HandlerMapping:根据请求的 URL,DispatcherServlet 使用 HandlerMapping 来确定哪个控制器应该处理该请求。
选择 HandlerAdapter:找到合适的 HandlerAdapter 来执行选定的控制器。
执行控制器方法:HandlerAdapter 调用控制器中的相应方法,并传递必要的参数(如路径变量、请求参数等)。
处理业务逻辑:控制器方法内部可能涉及到调用服务层、访问数据库等操作,完成相应的业务逻辑。
- 如控制器中未使用@ResponseBody
- 返回 ModelAndView:控制器方法完成后,通常会返回一个包含模型数据和视图名称的 ModelAndView 对象。
- 解析视图:DispatcherServlet 使用 ViewResolver 将视图名称转换为实际的视图对象。
- 渲染视图:使用解析后的视图对象,结合模型数据生成最终的响应内容(如 HTML 页面)。
- 发送响应:将生成的内容发送回客户端展示给用户。
- 如控制器中使用@ResponseBody:返回数据即可
配置拦截器
- 控制器中存在异常
- 执行异常处理器
- 拦截器中preHandle()及afterCompletion()会执行,postHandle()不会执行
- 控制器中不存在异常
- 不执行异常处理器
- 拦截器中所有方法正常执行