找回密码
 会员注册
查看: 29|回复: 0

在SpringBoot中使用Filters实现请求过滤和预处理

[复制链接]

5

主题

0

回帖

16

积分

新手上路

积分
16
发表于 2024-9-11 11:47:39 | 显示全部楼层 |阅读模式
​ 博客主页:   南来_北往系列专栏:SpringBoot实战什么是过滤器过滤器(Filter)是一种在Web应用中用于拦截和处理HTTP请求和响应的对象。在JavaWeb开发中,过滤器是实现特定功能,如认证、日志记录和字符编码处理的重要工具。具体如下:过滤器的基本概念定义:过滤器是一种可以动态地拦截传入的请求和传出的响应,并对这些请求和响应进行预处理和后处理的对象。作用:过滤器可以检查和修改请求头和响应头、处理cookies、验证用户提交的数据等。过滤器的工作原理工作流程:当一个请求到达服务器时,它会首先通过过滤器链,每个过滤器都有机会对请求进行处理。如果请求通过了所有过滤器的检验,它最终会到达目标资源,如servlet或JSP页面。请求处理:在过滤器中可以通过修改请求对象来实现对请求数据的预处理,例如,可以对输入数据进行解码或者验证。响应处理:在放行请求后,还可以在过滤器中修改返回给用户的响应数据,例如,对输出数据进行编码或者压缩。过滤器的生命周期初始化:init方法在过滤器创建时被调用,用于初始化操作。这个方法只运行一次,一般用来读取配置文件和初始化资源。过滤请求:doFilter方法是实际执行过滤操作的地方,每次请求经过过滤器时都会被调用。在这个方法中可以实现具体的过滤逻辑,并通过FilterChain对象决定是否将请求传递到下一个过滤器或者目标资源。销毁:destroy方法在过滤器销毁之前被调用,用于释放资源。这也是只运行一次的方法,通常用于清理操作。过滤器的使用场景身份验证:用于检查用户是否已经登录,确保只有合法用户才能访问受保护的资源。日志记录:记录每个请求的信息,如IP地址、访问时间等,有助于网站管理和安全监控。字符编码处理:解决不同字符集之间的兼容问题,避免出现乱码。输入数据验证:对用户提交的数据进行格式和有效性验证,防止非法输入导致的安全问题。如何配置和使用过滤器注解方式:通过@WebFilter注解直接在过滤器类上指定拦截路径,这种方法更简单、直观。XML配置:在web.xml文件中配置和元素,以定义过滤器及其应用场景。综上所述,过滤器在Web应用中起着至关重要的作用,从请求预处理到响应后处理,都能有效地提高应用的安全性、可用性和用户体验。对于开发人员而言,掌握过滤器的使用是提升Web应用质量的重要手段。为什么我们需要过滤器过滤器在Web开发中扮演着至关重要的角色,它们用于增强、控制和修改HTTP请求和响应的处理。具体如下:为什么需要过滤器提高代码重用性:通过使用过滤器可以避免在多个Servlet或JSP页面中重复编写相同的代码,从而简化了代码维护并减少了冗余。实现全局功能:过滤器可以全局处理所有请求,从而统一实现如字符编码处理、敏感词汇过滤等功能。增强安全性:通过身份验证和授权,过滤器能够阻止未经授权的用户访问受保护的资源,提升应用的安全性。提供更好的用户体验:例如,过滤器可以用于网站的统一登录功能,用户只需一次登录即可访问所有受保护的资源,而无需多次认证。过滤器的工作原理及生命周期工作流程:当一个请求到达服务器时,它会首先通过过滤器链,每个过滤器都有机会对请求进行处理。如果请求通过了所有过滤器的检验,它最终会到达目标资源,如servlet或JSP页面。请求处理:在过滤器中可以通过修改请求对象来实现对请求数据的预处理,例如,对输入数据进行解码或验证。响应处理:在放行请求后,还可以在过滤器中修改返回给用户的响应数据,例如,对输出数据进行编码或压缩。生命周期方法:过滤器的生命周期包括init、doFilter和destroy三个方法。init方法在过滤器创建时调用,用于初始化操作;doFilter方法在实际请求处理中被调用;destroy方法在过滤器销毁前调用,用于释放资源。过滤器的主要应用场景字符编码处理:通过过滤器可以统一设置请求和响应的字符编码,避免出现乱码问题。这在处理不同语言环境的应用中尤其重要。权限验证:过滤器可以检查用户是否已经登录或是否有权访问某个资源。这样,只有合法用户才能访问受保护的资源。日志记录:过滤器可以记录每个请求的信息,如IP地址、访问时间等,有助于网站管理和安全监控。输入数据验证:过滤器可以对用户提交的数据进行格式和有效性验证,防止非法输入导致的安全问题。敏感信息过滤:过滤器可以过滤掉请求和响应中的敏感信息,如SQL注入攻击的字符串,确保数据传输的安全。如何在SpringBoot中使用过滤器创建过滤器类:实现javax.servlet.Filter接口,并覆盖doFilter方法以定义过滤器的逻辑。在doFilter方法中,可以对请求和响应进行处理,并通过调用FilterChain.doFilter()将请求传递给下一个过滤器或目标Servlet。注册过滤器:使用@WebFilter注解将过滤器类标记为过滤器,并通过urlPatterns属性指定要拦截的URL模式。如果不使用@WebFilter注解,也可以通过在SpringBoot配置类中使用FilterRegistrationBean来注册过滤器。先创建一个FilterRegistrationBean实例,然后设置过滤器实例,添加URL模式,并设置优先级。过滤器与拦截器的区别处理范围:过滤器主要作用于Servlet容器层次,可以拦截所有到达Web应用的请求;而拦截器则作用于SpringMVC框架内,只能拦截由DispatcherServlet管理的请求。执行顺序:过滤器的执行顺序依赖于它们在web.xml中的配置顺序或通过@WebFilter注解声明的顺序;拦截器的执行顺序则依赖于在Spring配置文件中的声明顺序。功能实现:过滤器更侧重于请求的预处理和响应的后处理,比如字符编码处理、文件上传处理等;拦截器则更侧重于视图渲染前的控制器执行流程,如权限检查、表单验证等。综上所述,过滤器在Web应用的开发中起着至关重要的作用。从请求预处理到响应后处理,过滤器都能有效地提高应用的安全性、可用性和用户体验。对于开发人员而言,掌握过滤器的使用是提升Web应用质量的重要手段。创建过滤器要在SpringBoot中创建过滤器,您可以实现javax.servlet.Filter接口或扩展OncePerRequestFilter类。OncePerRequestFilter确保您的过滤器每个请求只执行一次。@RestController@RequestMapping("/customer")publicclassCustomerController{@GetMappingpublicStringgetMessage(){return"welcometofiltersession";}}@Component@Slf4jpublicclassMessageFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{log.info("[MessageFilter]-InsidedoFiltermethod");log.info("LocalPort:"+request.getLocalPort());log.info("ServerName:"+request.getServerName());HttpServletRequesthttpServletRequest=(HttpServletRequest)request;log.info("MethodName:"+httpServletRequest.getMethod());log.info("RequestURI:"+httpServletRequest.getRequestURI());log.info("ServletPath:"+httpServletRequest.getServletPath());chain.doFilter(request,response);}}过滤器的顺序过滤器的应用顺序可以通过@Order注解或@Component@Slf4j@Order(2)publicclassMessageFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{log.info("[MessageFilter]-InsidedoFiltermethod");log.info("LocalPort:"+request.getLocalPort());log.info("ServerName:"+request.getServerName());HttpServletRequesthttpServletRequest=(HttpServletRequest)request;log.info("MethodName:"+httpServletRequest.getMethod());log.info("RequestURI:"+httpServletRequest.getRequestURI());log.info("ServletPath:"+httpServletRequest.getServletPath());chain.doFilter(request,response);}}@Component@Slf4j@Order(1)publicclassProductFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{log.info("[ProductFilter]-InsidedoFiltermethod");log.info("LocalPort:"+request.getLocalPort());log.info("ServerName:"+request.getServerName());HttpServletRequesthttpServletRequest=(HttpServletRequest)request;log.info("MethodName:"+httpServletRequest.getMethod());log.info("RequestURI:"+httpServletRequest.getRequestURI());log.info("ServletPath:"+httpServletRequest.getServletPath());chain.doFilter(request,response);}}注意:如果您只想打印MessageFilter并跳过ProductFilter要在访问/customer API时仅显示MessageFilter的日志,您需要有条件地绕过ProductFilter对/customer端点的过滤。您可以通过修改ProductFilter来跳过特定端点的过滤来实现这一点。@Component@Slf4j@Order(1)//确保此过滤器在MessageFilter之前执行publicclassProductFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequesthttpServletRequest=(HttpServletRequest)request;StringrequestURI=httpServletRequest.getRequestURI();if("/customer".equals(requestURI)){chain.doFilter(request,response);return;//跳过过滤器的其余部分}log.info("[ProductFilter]-InsidedoFiltermethod");log.info("LocalPort:"+request.getLocalPort());log.info("ServerName:"+request.getServerName());log.info("MethodName:"+httpServletRequest.getMethod());log.info("RequestURI:"+requestURI);log.info("ServletPath:"+httpServletRequest.getServletPath());chain.doFilter(request,response);}} 注册过滤器@ConfigurationpublicclassFilterConfig{@BeanpublicFilterRegistrationBeanloggingFilter(){FilterRegistrationBeanregistrationBean=newFilterRegistrationBean();registrationBean.setFilter(newMessageFilter());registrationBean.addUrlPatterns("/customer/*");//如果需要,指定URL模式returnregistrationBean;}} OncePerRequestFilterpublicclassProductFilterextendsOncePerRequestFilter{@OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{log.info("[ProductFilter]-InsidedoFiltermethod");log.info("LocalPort:"+request.getLocalPort());log.info("ServerName:"+request.getServerName());HttpServletRequesthttpServletRequest=(HttpServletRequest)request;log.info("MethodName:"+httpServletRequest.getMethod());log.info("RequestURI:"+httpServletRequest.getRequestURI());log.info("ServletPath:"+httpServletRequest.getServletPath());filterChain.doFilter(request,response);}}简单案例1、建一个新的Java类,并实现javax.servlet.Filter接口。例如,创建一个名为MyFilter的类:importjavax.servlet.*;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;publicclassMyFilterimplementsFilter{@Overridepublicvoidinit(FilterConfigfilterConfig)throwsServletException{//初始化代码(可选)}@OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequesthttpRequest=(HttpServletRequest)request;//在这里可以对请求进行预处理操作,例如检查请求头、参数等//继续执行过滤器链中的下一个过滤器或目标资源chain.doFilter(request,response);//在这里可以对响应进行后处理操作,例如修改响应头、内容等}@Overridepublicvoiddestroy(){//销毁代码(可选)}}2、在SpringBoot应用程序的配置类上添加@Configuration注解,并在该类中定义一个方法,该方法返回一个带有@Bean注解的FilterRegistrationBean实例。这将注册你的过滤器并将其添加到过滤器链中。importorg.springframework.boot.web.servlet.FilterRegistrationBean;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;@ConfigurationpublicclassFilterConfig{@BeanpublicFilterRegistrationBeanmyFilter(){FilterRegistrationBeanregistrationBean=newFilterRegistrationBean();registrationBean.setFilter(newMyFilter());registrationBean.addUrlPatterns("/api/*");//设置过滤器应用于哪些URL模式registrationBean.setOrder(1);//设置过滤器的顺序(数字越小,优先级越高)returnregistrationBean;}}在上面的示例中,我们为MyFilter设置了URL模式/api/*,这意味着它将应用于所有以/api/开头的请求。你可以根据需要调整URL模式。3、现在,每当有匹配的请求到达时,MyFilter就会被调用,你可以在doFilter方法中编写自定义的请求过滤和预处理逻辑。同样地,你也可以在响应返回给客户端之前对其进行后处理。这样,你就成功地在SpringBoot应用程序中实现了请求过滤和预处理功能。记得根据你的需求调整过滤器的逻辑和配置。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-31 05:59 , Processed in 0.536782 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表