添加拦截器

本文详细介绍了Spring MVC的拦截器功能,包括如何实现HandlerInterceptor接口,注册拦截器,过滤拦截请求,以及拦截器方法的执行流程。在拦截器中,可以进行预处理、后续处理和异常处理。通过重写`preHandle`、`postHandle`和`afterCompletion`方法,可以实现请求的鉴权、请求过滤和异常处理。文章还探讨了多拦截器的执行顺序,并给出了实际应用场景的例子。

添加拦截器

当我们需要在所有的请求处理之前,先做一些预处理,或者在请求处理之后做一些后续处理,或者在处理执行流程中如果有异常则执行一段出错逻辑,这时候我们可以使用Spring MVC的拦截器功能

事实上这个功能很常用,他的逻辑类似Spring的AOP,在所有的请求处理逻辑之上增加一些增强逻辑

HandlerInterceptor接口

首先创建一个拦截器类,并实现HandlerInterceptor接口

public class MyInterceptor implements HandlerInterceptor {
}

实现了这个接口之后,我们可以看到可以重写三个方法

在这里插入图片描述

这三个方法都有默认实现,我们想要实现什么拦截效果,就重写对应的方法即可,首先介绍preHandle方法

preHandle方法是在请求处理方法之前执行的,他有一个布尔类型的返回参数,返回true则表示放行该请求,返回false则拦截该请求,我们常使用这个功能来做简单的鉴权功能

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行前置处理方法");
        System.out.println(request.getRequestURI());
        return true;
    }
}

参数列表中的HttpServletRequest 类可以帮助获取到被拦截的请求的请求信息,用于定制拦截逻辑

当我们返回false值时,拦截器拦截该请求,这个时候浏览器会得到一个空白页面,这个时候可以用参数列表中的HttpServletResponse类来设置页面转发或重定向到登录页面或者初始页面

注册拦截器

创建完拦截器之后,我们需要在Spring MVC配置类中添加这个拦截器,这样拦截器才能生效

重写WebMvcConfigurer接口中的addInterceptors方法来注册拦截器,然后用addPathPatterns方法来绑定需要拦截的请求,如果需要拦截所有的请求,可以使用/**来表示

@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}

编写一个请求方法来测试拦截结果

@RestController
public class MyController {

    @RequestMapping("/test")
    public String test() {
        System.out.println("执行请求处理方法");
        return "SUCCESS";
    }
}

测试结果如下,执行了拦截器中的preHandle方法,也获取到了拦截到的uri

在这里插入图片描述

过滤拦截请求

在绑定拦截的请求时,使用/**来拦截所有请求,但是其中有某些请求我们又不想拦截时,可以使用excludePathPatterns方法来过滤拦截请求,这种情况最常见的场景就是过滤静态资源请求,或者过滤登录页的请求

假如我有一张静态资源图片,而静态资源请求,一般是不需要拦截的

在这里插入图片描述

这时候可以先给静态资源的访问路径先加上一个请求前缀

spring:
  mvc:
    static-path-pattern: /static/**

这时候访问静态资源需要加上/static这个前缀

然后在配置拦截器的时候过滤/static/**请求就行了

@Configuration
public class MyWebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns("/static/**");
    }
}

拦截器方法的执行流程

除了preHandle方法,HandlerInterceptor接口还有另外两个方法

postHandle方法用于在请求方法执行结束后执行一段逻辑,afterCompletion方法用于在视图渲染完成后执行一段逻辑

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("执行preHandle方法");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("执行postHandle方法");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行afterCompletion方法");
    }
}

发送一个测试请求

在这里插入图片描述

可以发现他们的执行先后顺序是

  1. 执行preHandle方法
  2. 执行请求处理方法
  3. 执行postHandle方法
  4. 执行afterCompletion方法

执行出现异常时

当执行过程出现异常时,无论是preHandle方法,请求处理方法,还是postHandle方法出现了异常,都会触发afterCompletion方法,并且可以通过afterCompletion方法参数列表中的Exception类来获取异常信息

public class MyInterceptor implements HandlerInterceptor {
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("执行afterCompletion方法");
        System.out.println(ex.getMessage());
    }
}

我们在请求处理方法中模拟一个异常,测试结果

@RestController
public class MyController {

    @RequestMapping("/test")
    public String test() {
        System.out.println("执行请求处理方法");
        throw new RuntimeException("模拟异常");
    }
}

在这里插入图片描述

可以看到在发生异常时,会触发afterCompletion方法,并且可以获取到异常的信息

多拦截器执行流程

当有多个拦截器时,执行顺序如下图

在这里插入图片描述

  1. 顺序执行所有拦截器的preHandle方法
    • 如果preHandle方法返回true,执行下一个preHandle方法
    • 如果preHandle方法返回false,倒序执行所有已经执行过的拦截器的afterCompletion方法
  2. 如果所有preHandle方法返回true,执行请求处理方法,否则不执行
  3. 如果执行了请求处理方法,倒序执行所有拦截器的postHandle方法
    • 前面的所有步骤,如果有发生异常,则倒序执行所有已经执行过的拦截器的afterCompletion方法
    • 如果无异常,则倒序执行所有拦截器的afterCompletion方法
<think> 首先,用户的问题是关于在Retrofit中添加拦截器的方法。用户提供了三个引用内容,这些引用描述了如何添加拦截器、设置Cookie和添加缓存拦截器。 用户引用的内容: - 引用[1]:展示了在OkHttpClient中添加拦截器,并设置给Retrofit。 - 引用[2]:解释了Retrofit使用OkHttp的拦截器添加请求头,如Cookie。 - 引用[3]:列出了依赖项,包括OkHttp、Logging Interceptor、Retrofit等。 用户的问题是:“我想查找在Retrofit中添加拦截器的方法 请问如何在Retrofit中添加拦截器”。所以,我需要提供一个清晰的步骤,解释如何在Retrofit中添加拦截器。 系统级指令: 1. 行内数学表达式使用$...$,但这里可能不涉及数学,所以可能不需要。 2. 独立公式使用$$...$$,但同样,可能不适用。 3. LaTeX语法正确:确保任何数学表达式正确。 4. 使用中文回答:整个回答必须是中文。 5. 生成相关问题:在回答末尾添加相关问题。 6. 回答中引用的段落末尾自然地添加引用标识,例如[^1]:既然用户提供了引用,我需要引用它们。 7. 用户可见层:回答结构清晰,逐步解决问题,保证真实可靠。 从引用中,我可以提取关键步骤: - 在OkHttpClient中添加拦截器。 - 然后设置这个OkHttpClient给Retrofit。 步骤总结: 1. 创建OkHttpClient实例。 2. 添加拦截器到OkHttpClient(例如,LogInterceptor)。 3. 构建OkHttpClient。 4. 在创建Retrofit实例时,设置这个OkHttpClient。 引用[1]显示了代码示例:添加拦截器到OkHttpClient,然后设置给Retrofit。 引用[2]提到通过拦截器设置请求头,如Cookie。 引用[3]列出了必要的依赖项。 在回答中,我应该: - 先解释什么是拦截器拦截器是OkHttp的功能,允许在发送请求或接收响应前修改请求或响应。 - 然后给出添加拦截器的步骤。 - 提供代码示例(用中文解释)。 - 引用提供的引用内容。 - 确保回答真实可靠:基于我的知识和引用内容。 结构建议: 1. 介绍拦截器的作用。 2. 步骤:如何添加拦截器。 3. 代码示例。 4. 注意事项(如依赖项)。 5. 引用。 6. 生成相关问题。 相关问题:基于主题生成相关问题,例如: - 如何添加自定义拦截器? - 拦截器有哪些常见用途? - 如何添加日志拦截器或缓存拦截器? 最终回答: - 使用中文。 - 结构清晰。 - 末尾添加相关问题。 </think> 在Retrofit中添加拦截器是通过OkHttpClient实现的,因为Retrofit底层使用OkHttp进行网络请求。拦截器允许你在请求发送前或响应接收后进行拦截和修改,例如添加日志、设置请求头或缓存。以下是详细步骤和代码示例,基于引用内容和我对Retrofit的深入理解[^1][^2]。 ### 步骤1: 添加依赖项 首先,确保在项目的`build.gradle`文件中添加OkHttp和Retrofit的依赖。引用[3]中提到的依赖是基础: ```groovy dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.3' // 推荐使用最新版本 implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // 可选,用于JSON解析 } ``` - **注意**:版本号建议更新到当前最新版(如OkHttp 4.x),引用[3]使用的是旧版,升级可避免兼容性问题。 ### 步骤2: 创建拦截器 拦截器需要实现`Interceptor`接口。例如,创建一个日志拦截器来打印请求和响应数据(基于引用[1]的`LogInterceptor`): ```java public class LogInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); // 打印请求URL和头信息 Log.d("Retrofit", "Request URL: " + request.url()); Log.d("Retrofit", "Request Headers: " + request.headers()); Response response = chain.proceed(request); // 发送请求 // 打印响应信息 Log.d("Retrofit", "Response Code: " + response.code()); Log.d("Retrofit", "Response Body: " + response.body().string()); return response; } } ``` - 这个拦截器用于调试,类似引用[1]中的示例。如果是添加Cookie(如引用[2]),可以在拦截器中修改请求头: ```java public class CookieInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request originalRequest = chain.request(); Request newRequest = originalRequest.newBuilder() .header("Cookie", "your_cookie_value") // 添加Cookie头 .build(); return chain.proceed(newRequest); } } ``` ### 步骤3: 将拦截器添加到OkHttpClient 创建`OkHttpClient`实例,并添加拦截器。然后设置给Retrofit(基于引用[1]和引用[2]): ```java OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(new LogInterceptor()) // 添加日志拦截器 .addInterceptor(new CookieInterceptor()) // 添加Cookie拦截器(可选) .build(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) // 关键:设置自定义的OkHttpClient .addConverterFactory(GsonConverterFactory.create()) // 添加Gson转换器 .build(); ``` - **解释**: - `addInterceptor()`方法用于添加应用级拦截器(在请求发送前执行)。 - 如果添加网络级拦截器(如缓存),使用`addNetworkInterceptor()`。 - 设置`.client(okHttpClient)`将拦截器绑定到Retrofit,确保所有请求都经过拦截器处理[^1][^2]。 ### 步骤4: 使用Retrofit实例 创建API接口并发送请求: ```java public interface ApiService { @GET("users") Call<List<User>> getUsers(); } ApiService service = retrofit.create(ApiService.class); Call<List<User>> call = service.getUsers(); call.enqueue(new Callback<List<User>>() { @Override public void onResponse(Call<List<User>> call, Response<List<User>> response) { // 处理响应 } @Override public void onFailure(Call<List<User>> call, Throwable t) { // 处理错误 } }); ``` ### 注意事项 - **性能影响**:拦截器会增加请求处理时间,避免在拦截器中执行耗时操作。 - **缓存拦截器**:要添加缓存(如引用[3]提到的),在`OkHttpClient`中添加缓存拦截器: ```java .addNetworkInterceptor(new CacheInterceptor()) // 自定义缓存逻辑 ``` - **版本兼容**:OkHttp 4.x与Retrofit 2.x兼容,但需确保依赖一致[^3]。 通过以上步骤,你可以轻松为Retrofit添加拦截器,实现日志、认证或缓存功能[^1][^2][^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值