SpringMVC

SpringMVC

鸣谢:黑马程序员

文章目录

  • SpringMVC
    • 一、MVC
    • 二、SpringMVC入门
      • 1.概述
      • 2.入门案例
        • [2.1 使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标](#2.1 使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标)
        • [2.2 创建SpringMVC控制器类](#2.2 创建SpringMVC控制器类)
        • [2.3 初始化SpringMVC环境,让SpringMVC加载对应的`bean`](#2.3 初始化SpringMVC环境,让SpringMVC加载对应的bean)
        • [2.4 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC要处理的请求](#2.4 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC要处理的请求)
      • 3.入门案例的工作流程
        • [3.1 启动服务器并初始化](#3.1 启动服务器并初始化)
        • [3.2 单次请求](#3.2 单次请求)
      • 4.同时加载Spring和SpringMVC
        • [4.1 重构`ServletContainerInitConfig`类](#4.1 重构ServletContainerInitConfig类)
        • [4.2 `Controller`与业务`Bean`的加载控制](#4.2 Controller与业务Bean的加载控制)
        • [4.3 简化4.1代码](#4.3 简化4.1代码)
    • 三、请求与响应
      • 1.请求映射路径:`@RequestMapping`
      • 2.GET请求传参
        • [2.1 普通参数](#2.1 普通参数)
          • [P1 概述](#P1 概述)
          • [P2 请求参数名与形参名不一致的情况:`@RequestParam`](#P2 请求参数名与形参名不一致的情况:@RequestParam)
        • [2.2 POJO参数](#2.2 POJO参数)
        • [2.3 嵌套POJO参数](#2.3 嵌套POJO参数)
        • [2.4 数组参数](#2.4 数组参数)
        • [2.5 集合参数:`@RequestParam`](#2.5 集合参数:@RequestParam)
        • [2.6 通过json格式传参:`@RequestBody`](#2.6 通过json格式传参:@RequestBody)
          • [P0 准备工作](#P0 准备工作)
          • [P1 集合参数](#P1 集合参数)
          • [P2 POJO参数](#P2 POJO参数)
          • [P3 POJO集合参数](#P3 POJO集合参数)
        • [2.7 日期参数](#2.7 日期参数)
      • 3.POST请求传参
        • [P1 概述](#P1 概述)
        • [P2 POST请求中文乱码处理](#P2 POST请求中文乱码处理)
        • [2.8 类型转换器](#2.8 类型转换器)
      • 4.响应json数据
        • [4.0 准备工作](#4.0 准备工作)
        • [4.1 代码演示](#4.1 代码演示)
        • [4.2 `@ResponseBody`注解](#4.2 @ResponseBody注解)
    • 四、REST风格
    • 五、拦截器
      • 1.概述
      • 2.入门案例
        • [2.1 创建拦截器类`ProjectInterceptor`,并实现`HandlerInterceptor`接口](#2.1 创建拦截器类ProjectInterceptor,并实现HandlerInterceptor接口)
        • [2.2 创建配置类`SpringMvcSupport`,继承`WebMvcCofigurationSupport`,并实现`addInterceptors()`方法](#2.2 创建配置类SpringMvcSupport,继承WebMvcCofigurationSupport,并实现addInterceptors()方法)
        • [2.3 在`SpringMvcConfig`中扫描`com.zsh.config`这个包使拦截器生效](#2.3 在SpringMvcConfig中扫描com.zsh.config这个包使拦截器生效)
        • [2.4 使用标准接口`WebMvcConfigurer`简化2.2+2.3](#2.4 使用标准接口WebMvcConfigurer简化2.2+2.3)
        • [2.5 拦截器执行流程](#2.5 拦截器执行流程)
      • 3.拦截器参数
        • [3.1 前置处理器](#3.1 前置处理器)
        • [3.2 后置处理器](#3.2 后置处理器)
        • [3.3 完成后处理器](#3.3 完成后处理器)
      • 4.拦截器链的执行顺序

一、MVC

1.概述

  • MVC(Model-View-Controller)是一种广泛使用的软件架构模式,用于组织应用程序的代码结构,使其更加模块化,增强软件系统的可维护性和可扩展性。
  • MVC将应用程序分为3个主要组件:Model(模型)、View(视图)和Controller(控制器)。

2.组件职能

图源:https://medium.com/@sadikarahmantanisha/the-mvc-architecture-97d47e071eb2

2.1 模型
  • 模型是MVC架构中的核心
  • 主要负责数据和业务逻辑:
    • 与数据库或其他数据源交互,处理数据的CRUD操作。
  • 模型与视图和控制器相互独立,不直接与用户界面相关联。
  • 模型的变化通常由控制器触发,并最终反映到视图中。
2.2 视图
  • 视图是MVC架构中的表现层
  • 主要负责将模型中的数据以用户可见的形式展示到用户界面:
    • 接收控制器传递的数据,进行展示和简单格式化。
  • 视图通常是静态的,不包含业务逻辑。
2.3 控制器
  • 控制器是模型和视图的中介
  • 主要负责处理用户请求:
    • 接收用户请求(如点击、表单提交),并调用相应的模型方法处理数据,根据处理结果选择合适的视图,并将数据传递给视图进行展示。


二、SpringMVC入门

!Tip

SpringMVC技术与Servlet技术等同,均属于Web层(别名:表现层、接口层)开发技术,前者明显优于后者。

1.概述



  • SpringMVC是一种基于Java实现MVC软件架构模型的轻量级Web框架(别名:表现层框架、接口层框架)

  • 优点:使用简单,开发便捷,灵活性强。


2.入门案例

2.1 使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标
xml 复制代码
<!--1.导入SpringMVC与Servlet的坐标-->
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>javax.servlet-api</artifactId>
  <version>版本</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>版本</version>
</dependency>
2.2 创建SpringMVC控制器类
java 复制代码
// 2.定义controller
@Controller// 使用@Controller来定义bean
public class UserController {

    @RequestMapping("/save")// 设置当前操作的访问路径
    @ResponseBody// 将方法返回值设置为当前操作的响应体
    public String save(){
        System.out.println("user save ...");
        return "{'module':'springmvc'}";
    }
}
2.3 初始化SpringMVC环境,让SpringMVC加载对应的bean
java 复制代码
// 3.创建SpringMVC的配置文件,加载Controller对应的bean
@Configuration
@ComponentScan("com.zsh.controller")
public class SpringMvcConfig {
}
2.4 初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC要处理的请求
java 复制代码
// 4.定义一个Servlet容器启动的配置类,在里面加载SpringMVC的配置
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer{
    @Override
    // 加载SpringMVC容器配置
    protected WebApplicationContext createServletApplicationContext() {
        AnnotationConfigWebApplicationContext context=new AnnotationConfigWebApplicationContext();// 注意类名不要写错,有个Web 
        context.register(SpringMvcConfig.class);
        return context;
    }

    @Override
    // 设置哪些请求交由SpringMVC处理
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    // 加载Spring容器配置
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
}

3.入门案例的工作流程

3.1 启动服务器并初始化
  1. 服务器启动,执行ServletContainerInitConfig类,初始化Web容器。
  2. 执行ServletContainerInitConfig类中的createServletApplicationContext()方法,创建一个WebApplicationContext对象。
  3. 加载SpringMvcConfig类。
  4. 通过SpringMvcConfig类中的@ComponentScan注解加载对应的bean
  5. 加载UserController类,每个@RequestMapping的名称对应一个具体方法。
  6. 执行ServletContainerInitConfig类中的getServletMappings()方法,设置所有请求都交由SpringMVC处理。
3.2 单次请求
  1. 发送请求localhost:8082/save。(8082是我设置的Tomcat端口,可以自定义修改)
  2. Web容器将所有请求都交由SpringMVC处理。
  3. 解析请求路径/save
  4. /save映射到对应方法save()
  5. 执行save()方法。
  6. 检测到save()方法带有@ResponseBody注解,直接将save()方法的返回值作为响应体返回给请求方。

4.同时加载Spring和SpringMVC

4.1 重构ServletContainerInitConfig
java 复制代码
public class ServletContainerInitConfig extends AbstractDispatcherServletInitializer{
    @Override
    protected WebApplicationContext createRootApplicationContext() {// Root
        AnnotationConfigWebApplicationContext context=new AnnotationConfigWebApplicationContext();
        context.register(SpringConfig.class);// 加载Spring
        return context;
    }
    
    @Override
    protected WebApplicationContext createServletApplicationContext() {// Servlet
        AnnotationConfigWebApplicationContext context=new AnnotationConfigWebApplicationContext();
        context.register(SpringMvcConfig.class);// 加载SpringMVC
        return context;
    }
    
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
4.2 Controller与业务Bean的加载控制
  • SpringMVC加载的bean均在com.zsh.controller包内。

  • 如何避免Spring错误加载SpringMVC控制的bean

    • 方式一(推荐) :Spring加载的bean设定扫描范围为精确范围。如@ComponentScan({"com.zsh.service", "com.zsh.dao"})

    • 方式二 :Spring加载的bean设定扫描范围为com.zsh,同时排除掉controller包内的bean

      java 复制代码
      // @Configuration这个注解必须去掉,否则过滤无效
      @ComponentScan("com.zsh.controller")
      public class SpringMvcConfig {
      }
      java 复制代码
      @Configuration
      @Component(value = "com.zsh", 
      	excludeFilters = @ComponentScan.Filter(
      		type = FilterType.ANNOTATION,// 按注解过滤
      		classes = Controller.class// 过滤掉带@Controller注解的bean
      	)
      )
      public class SpringConfig {
      }
    • 方式三:不区分Spring与SpringMVC的环境,加载到同一环境中。

4.3 简化4.1代码
java 复制代码
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer{
    
   	@Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringConfig.class};
    }
    
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}


三、请求与响应

1.请求映射路径:@RequestMapping

@RequestMapping注解既可用于方法上,也可用于整个类上,这时候的作用是统一设置当前类的方法的请求映射路径前缀。示例如下:

java 复制代码
@Controller
@RequestMapping("/user")// 请求路径前缀
public class UserController {

    @RequestMapping("/save")
    @ResponseBody
    public String save(){
        System.out.println("user save ...");
        return "{'module':'user save'}";
    }

    @RequestMapping("/delete")
    @ResponseBody
    public String delete(){
        System.out.println("user delete ...");
        return "{'module':'user delete'}";
    }
}

2.GET请求传参

2.1 普通参数
P1 概述

传参方式:url地址直接传参,地址参数名与形参名一致,在方法签名里定义形参即可接收参数。

java 复制代码
@Controller
public class UserController {
    // 普通参数
    @RequestMapping("/commonParam")
    @ResponseBody
    public String commonParam(String name, int age){
        System.out.println("common param: name ==> "+name);
        System.out.println("common param: age ==> "+age);
        return "{'module':'common param'}";
    }
}
P2 请求参数名与形参名不一致的情况:@RequestParam
java 复制代码
@Controller
public class UserController {
    // 普通参数:请求参数名与形参名不一致的情况
    @RequestMapping("/commonParamDifferentName")
    @ResponseBody
    public String commonParamDifferentName(@RequestParam("name") String userName, int age){
        System.out.println("common param: name ==> "+userName);
        System.out.println("common param: age ==> "+age);
        return "{'module':'common param different name'}";
    }
}

2.2 POJO参数

!Tip

POJO(Plain Ordinary Java Object):简单的Java对象,实际上就是普通的JavaBean,只是为了避免和EJB混淆所创造的简称。

java 复制代码
@Controller
public class UserController {
    // POJO参数
    @RequestMapping("/pojoParam")
    @ResponseBody
    public String pojoParam(User user){
        System.out.println("pojo param: user ==> "+user);
        return "{'module':'pojo param'}";
    }
}

2.3 嵌套POJO参数
java 复制代码
@Controller
public class UserController {
    // 嵌套POJO参数
    @RequestMapping("/pojoContainsPojoParam")
    @ResponseBody
    public String pojoContainsPojoParam(User user){
        System.out.println("pojo param: user ==> "+user);
        return "{'module':'pojo contains pojo param'}";
    }
}

2.4 数组参数
java 复制代码
@Controller
public class UserController {
    // 数组参数
    @RequestMapping("/arrayParam")
    @ResponseBody
    public String arrayParam(String[] hobbies){
        System.out.println("array param: hobbies ==> "+ Arrays.toString(hobbies));
        return "{'module':'array param'}";
    }
}

2.5 集合参数:@RequestParam
java 复制代码
@Controller
public class UserController {
    // 集合参数
    @RequestMapping("/listParam")
    @ResponseBody
    public String listParam(@RequestParam List<String> hobbies){// 此处必须加@RequestParam注解来绑定参数关系,否则报错
        System.out.println("list param: hobbies ==> "+ hobbies);
        return "{'module':'list param'}";
    }
}

2.6 通过json格式传参:@RequestBody
P0 准备工作

首先要导入json坐标,才能进行接下来的步骤!

xml 复制代码
<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>版本</version>
    </dependency>
</dependencies>

其次要在SpringMvcConfig中新增注解@EnableWebMvc

java 复制代码
@Configuration
@ComponentScan("com.zsh.controller")
@EnableWebMvc// 其中一个功能:对json数据进行自动类型转换
public class SpringMvcConfig {
}
P1 集合参数
java 复制代码
@Controller
public class UserController {   
    // 集合参数:json
    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> hobbies){// 此处必须加@RequestBody注解来绑定参数关系
        System.out.println("list param json: hobbies ==> " + hobbies);
        return "{'module':'list param for json'}";
    }
}
P2 POJO参数
java 复制代码
@Controller
public class UserController {
    // POJO参数:json
    @RequestMapping("/pojoParamForJson")
    @ResponseBody
    public String pojoParamForJson(@RequestBody User user){// 此处必须加@RequestBody注解来绑定参数关系
        System.out.println("pojo param json: user ==> " + user);
        return "{'module':'pojo param for json'}";
    }
}
P3 POJO集合参数
java 复制代码
@Controller
public class UserController {
    // POJO集合参数:json
    @RequestMapping("/pojoListParamForJson")
    @ResponseBody
    public String pojoListParamForJson(@RequestBody List<User> users){// 此处必须加@RequestBody注解来绑定参数关系
        System.out.println("pojo list param json: users ==> " + users);
        return "{'module':'pojo list param for json'}";
    }
}

2.7 日期参数

!Tip

Spring默认的标准日期格式是yyyy/MM/dd

java 复制代码
@Controller
public class UserController {
    // 日期参数
    @RequestMapping("/dateParam")
    @ResponseBody
    public String dateParam(
            Date date1,
            @DateTimeFormat(pattern = "yyyy-MM-dd") Date date2,
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") Date date3
    ){
        System.out.println("date param: date1 ==> "+date1);
        System.out.println("date param: date2(yyyy-MM-dd) ==> "+date2);
        System.out.println("date param: date3(yyyy-MM-dd HH:mm:ss) ==> "+date3);
        return "{'module':'date param'}";
    }
}

3.POST请求传参

P1 概述

传参方式 :请求体里通过x-www-for-urlencoded表单传参,表单参数名与形参名一致,在方法签名里定义形参即可接收参数。

java 复制代码
@Controller
public class UserController {

    // 普通参数
    @RequestMapping("/commonParam")
    @ResponseBody
    public String commonParam(String name, int age){
        System.out.println("common param: name ==> "+name);
        System.out.println("common param: age ==> "+age);
        return "{'module':'common param'}";
    }
}
P2 POST请求中文乱码处理
java 复制代码
public class ServletContainerInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[0];
    }

    // POST请求中文乱码处理:设置过滤器
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter filter=new CharacterEncodingFilter();
        filter.setEncoding("UTF-8");
        return new Filter[]{filter};
    }
}

2.8 类型转换器

4.响应json数据

4.0 准备工作

首先要导入json坐标,才能进行接下来的步骤!

xml 复制代码
<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>版本</version>
    </dependency>
</dependencies>

其次要在SpringMvcConfig中新增注解@EnableWebMvc

java 复制代码
@Configuration
@ComponentScan("com.zsh.controller")
@EnableWebMvc// 其中一个功能:对json数据进行自动类型转换
public class SpringMvcConfig {
}
4.1 代码演示
  • page.jsp:

    jsp 复制代码
    <html>
    <body>
    <h2>Hello SpringMVC!</h2>
    </body>
    </html>
  • UserController:

    java 复制代码
    @Controller
    public class UserController {
        // 响应页面/跳转页面
        @RequestMapping("/toJumpPage")
        public String toJumpPage(){
            System.out.println("jump page");
            return "page.jsp";
        }
    
        // 响应文本数据
        @RequestMapping("/toText")
        @ResponseBody
        public String toText(){
            System.out.println("return text");
            return "response text";
        }
    
        // 响应POJO:json
        @RequestMapping("/toJsonPojo")
        @ResponseBody
        public User toJsonPojo(){
            System.out.println("return json pojo");
            User user=new User("zsh",999);
            return user;
        }
    
        // 响应POJO集合:json
        @RequestMapping("/toJsonPojoList")
        @ResponseBody
        public List<User> toJsonPojoList(){
            System.out.println("return json pojo list");
            User user1=new User("aj",6);
            User user2=new User("swift",52);
            List<User> users=new ArrayList<>();
            users.add(user1);
            users.add(user2);
            return users;
        }
    }
4.2 @ResponseBody注解


四、REST风格

!Tip

REST(Representational State Transfer):表征性状态转换。

RESTful:使用REST风格对资源进行访问。

1.简介


2.RESTful入门案例:@PathVariable

2.1 代码演示
java 复制代码
@Controller
@RequestMapping("/users")// 请求路径前缀
public class UserController {

    @RequestMapping(method = RequestMethod.POST)
    @ResponseBody
    public String save(@RequestBody User user) {
        System.out.println("user save ... " + user);
        return "{'module':'user save'}";
    }

    // 我已设定了请求路径前缀
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @ResponseBody
    public String delete(@PathVariable Integer id) {// @PathVariable表示从url地址中取出id这个变量的值
        System.out.println("user delete ... " + id);
        return "{'module':'user delete'}";
    }

    @RequestMapping(method = RequestMethod.PUT)
    @ResponseBody
    public String update(@RequestBody User user) {
        System.out.println("user update ... " + user);
        return "{'module':'user update'}";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    @ResponseBody
    public String getById(@PathVariable Integer id) {
        System.out.println("user getById ... " + id);
        return "{'module':'user getById'}";
    }

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String getAll() {
        System.out.println("user getAll ...");
        return "{'module':'user getAll'}";
    }

}
2.2 注解区别
注解 作用 适用场景
@RequestParam 接收url地址传参或表单传参 发送非json格式的数据
@RequestBody 接收json传参 发送的请求参数超过1个且以json格式为主
@PathVariable 接收路径参数,使用{参数名称}来描述路径参数 采用RESTful进行开发,且参数数量较少。通常用于传递id值。

3.RESTful快速开发:@RestController@XxxMapping

java 复制代码
@RestController// 等价于@Controller + @ResponseBody
@RequestMapping("/books")
public class BookController {

//    @RequestMapping(method = RequestMethod.POST)
    @PostMapping
    public String save(@RequestBody Book book) {
        System.out.println("book save ... " + book);
        return "{'module':'book save'}";
    }

//    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
    @DeleteMapping("/{id}")
    public String delete(@PathVariable Integer id) {// @PathVariable表示从url地址中取出id这个变量的值
        System.out.println("book delete ... " + id);
        return "{'module':'book delete'}";
    }

    @PutMapping
    public String update(@RequestBody Book book) {
        System.out.println("book update ... " + book);
        return "{'module':'book update'}";
    }

    @GetMapping("/{id}")
    public String getById(@PathVariable Integer id) {
        System.out.println("book getById ... " + id);
        return "{'module':'book getById'}";
    }

    @GetMapping
    public String getAll() {
        System.out.println("book getAll ...");
        return "{'module':'book getAll'}";
    }
}

4.案例:基于RESTful的页面数据交互

详见:springmvc\06_REST_case



五、拦截器

1.概述

  • **拦截器(Interceptor)**是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行。
  • 作用
    • 在指定的方法调用前后执行预先设定的代码。
    • 根据需要阻止原始方法的执行。
  • 拦截器与过滤器(Filter)的区别:
    • 归属不同:过滤器属于Servlet技术,拦截器属于SpringMVC技术。
    • 拦截内容不同:过滤器对所有访问进行增强,拦截器只针对SpringMVC的访问进行增强。

2.入门案例

2.1 创建拦截器类ProjectInterceptor,并实现HandlerInterceptor接口
java 复制代码
@Component
public class ProjectInterceptor implements HandlerInterceptor {
    @Override
    // 拦截之前
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("pre handle ...");
        return true;// 若return false,则会阻止原始方法的执行
    }

    @Override
    // 拦截之后
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("post handle ...");
    }

    @Override
    // 完成后
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("after completion ...");
    }
}
2.2 创建配置类SpringMvcSupport,继承WebMvcCofigurationSupport,并实现addInterceptors()方法
java 复制代码
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {

    @Autowired
    private ProjectInterceptor interceptor;

    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        // 访问/books及其子目录,都需要经过拦截器
        registry.addInterceptor(interceptor).addPathPatterns("/books", "/books/*");
    }
}
2.3 在SpringMvcConfig中扫描com.zsh.config这个包使拦截器生效
java 复制代码
@Configuration
@ComponentScan({"com.zsh.controller", "com.zsh.config"})
@EnableWebMvc
public class SpringMvcConfig {
}
2.4 使用标准接口WebMvcConfigurer简化2.2+2.3

!Caution

此方法侵入式较强,与Spring紧耦合。

java 复制代码
@Configuration
//@ComponentScan({"com.zsh.controller", "com.zsh.config"})
@ComponentScan({"com.zsh.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 访问/books及其子目录,都需要经过拦截器
        registry.addInterceptor(interceptor).addPathPatterns("/books", "/books/*");
    }
}
2.5 拦截器执行流程

3.拦截器参数

3.1 前置处理器
java 复制代码
public boolean preHandle(
    HttpServletRequest request, 
    HttpServletResponse response, 
    Object handler) throws Exception 
{
    System.out.println("pre handle ...");
    return true;
}
  • 参数:
    • request:请求对象。
    • response:响应对象。
    • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装。
  • 返回值:若return false,则会阻止原始方法的执行。
3.2 后置处理器
java 复制代码
public void postHandle(
    HttpServletRequest request, 
    HttpServletResponse response, 
    Object handler, 
    ModelAndView modelAndView) throws Exception 
{
    System.out.println("post handle ...");
}
  • 参数modelAndView:如果处理器执行完成后具有返回结果,则可以读取到对应的数据与页面信息,并进行调整(现代开发已淘汰)。
3.3 完成后处理器
java 复制代码
public void afterCompletion(
    HttpServletRequest request, 
    HttpServletResponse response, 
    Object handler, 
    Exception ex) throws Exception 
{
    System.out.println("after completion ...");
}
  • 参数ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理(现代开发已淘汰)。

4.拦截器链的执行顺序

!TIP

当配置多个拦截器时,会形成拦截器链。

  • 参照代码中拦截器的添加顺序,先进后出,后进先出(类似于"栈")。
  • 当某个拦截器中的preHandler()方法返回了true,则后面 拦截器均被终止运行,仅运行前面 拦截器(不包括当前拦截器)的afterCompletion()方法。
相关推荐
用户8307196840822 小时前
Java 并发进化史:从踩坑到躺赢
java
傻啦嘿哟2 小时前
Python在Excel中创建与优化数据透视表的完整指南
java·前端·spring
uup2 小时前
异常的 “隐藏传递”:finally 中的 return 会吞噬异常?
java
白露与泡影2 小时前
春招 Java 面试大纲:Java+ 并发 +spring+ 数据库 +Redis+JVM+Netty 等
java·数据库·面试
roman_日积跬步-终至千里2 小时前
【多线程】 Spring 无状态 Service 线程安全设计实战
java·安全·spring
Yeniden2 小时前
Deepeek用大白话讲解 --> 状态模式(企业级场景1,自动售货机2,订单状态3,消除if-else4)
java·开发语言·状态模式
掉鱼的猫2 小时前
超越 SpringBoot 4.0了吗?OpenSolon v3.8, v3.7.4, v3.6.7 发布
java·spring boot
廋到被风吹走2 小时前
【Spring】InitializingBean 深度解析:Spring Bean 的“初始化回调接口“
java·后端·spring
andwhataboutit?2 小时前
LANGGRAPH
java·服务器·前端