如何优雅地使用Spring Boot拦截器提升应用的用户体验?

举报
bug菌 发表于 2023/10/11 17:07:23 2023/10/11
【摘要】 🏆本文收录于《Spring Boot从入门到精通》,专门攻坚指数提升,2023 年国内最系统+最强(更新中)。


🏆本文收录于《Spring Boot从入门到精通》,专门攻坚指数提升,2023 年国内最系统+最强(更新中)。

本专栏致力打造最硬核Spring Boot 系列教程,从零基础到进阶系列学习内容,🚀均为全网独家首发,打造精品专栏,专栏持续更新中…欢迎大家订阅持续学习。

环境说明:Windows10 + Idea2021.3.2 + Jdk1.8 + SpringBoot 2.3.1.RELEASE

前言

在Web开发中,经常需要对请求进行预处理或后处理,在Spring Boot中则采用拦截器的方式来实现。拦截器可以在请求到达Handler前或请求返回前做一些处理,比如验证用户的登录状态、记录日志、修改请求参数等。本文将介绍Spring Boot中的拦截器相关知识,并提供实例代码。

摘要

本文将介绍Spring Boot中的拦截器,包括拦截器的基本概念、使用方法、实现原理等。并提供一个简单的示例代码,通过该示例代码可以更好地理解拦截器的应用场景和实现方法。

拦截器

概念

拦截器是一种在Web开发中常用的处理机制,可以在请求到达Controller前或请求返回前做一些处理。拦截器和过滤器类似,但是拦截器更加灵活,可以拦截Controller中的方法调用,而过滤器只能拦截请求和响应。拦截器可以用于实现登录验证、权限控制、日志记录等功能。

在Spring Boot中,拦截器是通过实现HandlerInterceptor接口来实现的。

应用场景

拦截器主要用于对请求进行处理,在请求到达controller之前或之后对请求进行一些处理。

  1. 登录验证,比如用户请求某一个需要登录才能访问的接口时,先判断是否登录,未登录则跳转到登录界面,已登录则继续访问。
  2. 路径权限控制,在访问某一个路径时,根据登录用户的权限来判断是否可以访问,如不能访问则返回相应的错误信息。
  3. 日志记录,拦截器可以在请求到达或离开controller时记录一些请求相关信息,方便后续日志分析。
  4. 请求参数验证,拦截器可以对请求参数进行验证,如果参数不符合要求则返回相应的错误信息。

优缺点

优点

  1. 拦截器可以在请求到达controller之前或之后对请求进行处理,比如对请求参数进行验证、记录请求日志等。
  2. 拦截器可以对多个接口进行统一处理,提高代码复用性和开发效率。
  3. 拦截器可以进行链式拦截,如一个请求需要经过多个拦截器处理,可以配置多个拦截器按照一定的顺序进行处理。

缺点

  1. 拦截器只能对controller的请求进行处理,无法拦截到像静态资源等不经过controller的请求。
  2. 拦截器只能对请求进行处理,无法进行响应结果处理,如返回结果加密等操作。
  3. 拦截器可能会增加请求处理时间,对系统性能有一定的影响。

代码演示

首先,我们需要编写一个实现了HandlerInterceptor接口的拦截器类,如下所示:

public class MyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 在请求到达Controller前做一些处理
        return true; // 返回true表示继续执行,返回false表示中断执行
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在请求返回前做一些处理
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在请求完成后做一些处理
    }
}

其中,HandlerInterceptor接口有三个方法需要实现:

  • preHandle方法在请求到达Controller前执行,返回值表示是否继续执行,如果返回false表示中断执行。
  • postHandle方法在请求返回前执行,可以修改响应内容或重定向。
  • afterCompletion方法在请求完成后执行,可以做一些资源清理等工作。

接下来,我们需要在Spring Boot中注册该拦截器,有两种方式可以实现。

第一种方式是在WebMvcConfigurer接口中注册拦截器,如下所示:

@Configuration
public class WebConfig implements WebMvcConfigurer {

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

这种方式需要实现WebMvcConfigurer接口,并重写addInterceptors方法。通过registry.addInterceptor方法注册拦截器,并使用addPathPatterns方法指定需要拦截的请求路径。

第二种方式是通过注解方式来注册拦截器,如下所示:

@Configuration
public class InterceptorConfig {

    @Bean
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }

    @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                registry.addInterceptor(myInterceptor()).addPathPatterns("/**");
            }
        };
    }
}

这种方式需要使用@Configuration注解来声明InterceptorConfig类是一个配置类,通过@Bean注解将拦截器注册到Spring容器中,并通过WebMvcConfigurerAdapter类的子类来实现addInterceptors方法。与第一种方式相比,这种方式更加灵活,可以在拦截器中使用@Autowired等注解自动装配其他Spring组件。

实现原理

拦截器的实现依赖于Spring MVC框架中的HandlerInterceptor接口。当请求到达DispatcherServlet时,DispatcherServlet会依次调用注册在WebMvcConfigurer中的所有拦截器的preHandle方法,如果返回true则继续处理,否则返回错误信息。在Controller中的方法调用完成之后,DispatcherServlet会依次调用注册在WebMvcConfigurer中的所有拦截器的postHandle方法。

示例代码

以下示例代码演示了如何在Spring Boot中实现拦截器。假设我们需要实现登录状态的拦截器,当用户未登录时,返回错误信息,否则继续执行。

首先,我们需要在Spring Boot中实现一个登录功能,代码如下所示:

@RestController
public class LoginController {

    @PostMapping("/login")
    public String login(@RequestBody User user) {
        // 登录验证
        if ("admin".equals(user.getUsername()) && "123456".equals(user.getPassword())) {
            return "登录成功";
        } else {
            return "登录失败";
        }
    }
}

这里假设我们使用POST请求来登录,请求体中包含用户名和密码。

然后,我们需要实现一个拦截器来验证用户的登录状态,代码如下所示:

public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 判断用户是否登录
        HttpSession session = request.getSession();
        if (session.getAttribute("user") == null) {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            out.write("请先登录");
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

这里我们判断用户是否登录是根据Session中是否存在“user”属性来判断的。如果未登录,我们返回错误信息。

最后,我们需要将拦截器注册到Spring Boot中,代码如下所示:

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/hello");
    }
}

这里我们使用了第一种方式将拦截器注册到Spring Boot中,并指定了拦截路径为/hello。

最后,我们使用一个Controller类来测试拦截器的效果,代码如下所示:

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello World";
    }
}

这里我们定义了一个简单的/hello接口,请求该接口会返回“Hello World”字符串。

当我们未登录时,请求该接口会返回“请先登录”字符串。当我们登录后,请求该接口会正常返回“Hello World”字符串。

测试用例

以下是一个简单的测试用例,用于测试拦截器的效果:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class LoginInterceptorTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @Test
    public void testLoginInterceptor() {
        String response = restTemplate.getForObject("/hello", String.class);
        assertEquals("请先登录", response);

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>("{\"username\":\"admin\",\"password\":\"123456\"}", headers);
        restTemplate.postForObject("/login", entity, String.class);

        response = restTemplate.getForObject("/hello", String.class);
        assertEquals("Hello World", response);
    }
}

这里我们使用TestRestTemplate来发送HTTP请求,测试拦截器的效果。首先请求/hello接口,会返回“请先登录”字符串,然后通过/login接口登录,再次请求/hello接口,会正常返回“Hello World”字符串。

小结

本文通过一个简单的示例代码演示了如何在Spring Boot中实现拦截器,并使用测试用例测试了拦截器的效果。通过本文,我们可以了解到:

  1. 拦截器可以用于在请求被处理之前或之后,对请求进行相关的处理;
  2. 在Spring Boot中,可以通过实现HandlerInterceptor接口来实现拦截器;
  3. 可以使用两种方式将拦截器注册到Spring Boot中,一种是通过@Configuration配置类实现WebMvcConfigurer接口,另一种是使用@WebFilter注解;
  4. 常用的拦截器应用场景包括:登录验证、请求参数验证、请求日志记录等。

附录源码

  如上涉及所有源码均已上传同步在「GitHub」,提供给同学们一对一参考学习,辅助你更迅速的掌握。

总结

本文介绍了在Spring Boot中实现拦截器的方法,以一个登录状态验证的示例为例进行讲解。我们通过实现一个登录功能和一个拦截器来验证用户的登录状态,并将拦截器注册到Spring Boot中,验证了拦截器的效果。

总结来说,拦截器是Spring Boot中常用的一种功能,在需要对请求进行统一处理、验证登录状态等场景下非常有用。通过本文的学习,我们可以掌握拦截器的基本使用方法,并应用到实际的开发中去。

☀️建议/推荐你


无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学Spring Boot」,从入门到精通,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大,指数级提升。

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

📣关于我

我是bug菌,CSDN | 掘金 | InfoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。