SpringBoot添加filter,统计网关接口调用

一、背景
统计网关制定接口访问次数
二、实现代码

@Slf4j
public class GatewayFilter extends OncePerRequestFilter {

    private final ApplyService applyService;

    private final AsyncService asyncService;

    public GatewayFilter(ApplyService applyService, AsyncService asyncService) {
        this.applyService = applyService;
        this.asyncService = asyncService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String appId = request.getHeader("appId");
        String userId = request.getHeader("userId");
        String accessUrl = request.getRequestURI();
        log.info("网关接口headers,appId={},userId={},accessUrl={}", appId, userId, accessUrl);
        if (StrUtil.isBlank(appId)) {
            this.returnJson(response, ResultData.failed("网关接口缺少appId"));
        }
        Apply apply = applyService.selectByAppId(appId);
        if (apply == null) {
            this.returnJson(response, ResultData.failed("appId不合法"));
        }
        if (apply != null && apply.getEnable() == 0) {
            this.returnJson(response, ResultData.failed("appId未启用"));
        }
        AccessLog accessLog = new AccessLog();
        accessLog.setAppId(appId);
        accessLog.setUserId(userId);
        accessLog.setAccessUrl(accessUrl);
        asyncService.saveGatewayLog(accessLog);
        chain.doFilter(request, response);
    }

    private void returnJson(ServletResponse response, ResultData resultData) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try (OutputStream out = response.getOutputStream()) {
            out.write(JSONUtil.toJsonStr(resultData).getBytes(StandardCharsets.UTF_8));
            out.flush();
        } catch (IOException e) {
            log.error("response error:", e);
        }
        throw new BusinessException("appId异常");
    }

}
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Resource
    private ApplyService applyService;

    @Resource
    private AsyncService asyncService;

    @Bean
    public FilterRegistrationBean<GatewayFilter> registerGatewayFilter() {
        FilterRegistrationBean<GatewayFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new GatewayFilter(applyService, asyncService));
        registration.addUrlPatterns(
                "/gateway/getListByIds",
                "/gateway/getById"
        );
        registration.setName("gatewayFilter");
        registration.setOrder(1);
        return registration;
    }

}

统计结果:
网关接口统计调用次数
三、踩坑及解决办法
首先启动报错(我这里是用外部tomcat启动):

16-Aug-2021 11:53:41.756 严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardContext.startInternal 一个或多个筛选器启动失败。完整的详细信息将在相应的容器日志文件中找到

这个我看网上好多都把lib包导入,这里没用,看我开始的filter代码:

@Slf4j
public class GatewayFilter extends OncePerRequestFilter {

    @Resource
    private ApplyService applyService;
    
    @Resource
    private AsyncService asyncService;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        String appId = request.getHeader("appId");
        String userId = request.getHeader("userId");
        String accessUrl = request.getRequestURI();
        log.info("网关接口headers,appId={},userId={},accessUrl={}", appId, userId, accessUrl);
        if (StrUtil.isBlank(appId)) {
            this.returnJson(response, ResultData.failed("网关接口缺少appId"));
        }
        Apply apply = applyService.selectByAppId(appId);
        if (apply == null) {
            this.returnJson(response, ResultData.failed("appId不合法"));
        }
        if (apply != null && apply.getEnable() == 0) {
            this.returnJson(response, ResultData.failed("appId未启用"));
        }
        AccessLog accessLog = new AccessLog();
        accessLog.setAppId(appId);
        accessLog.setUserId(userId);
        accessLog.setAccessUrl(accessUrl);
        asyncService.saveGatewayLog(accessLog);
        chain.doFilter(request, response);
    }

    private void returnJson(ServletResponse response, ResultData resultData) {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try (OutputStream out = response.getOutputStream()) {
            out.write(JSONUtil.toJsonStr(resultData).getBytes(StandardCharsets.UTF_8));
            out.flush();
        } catch (IOException e) {
            log.error("response error:", e);
        }
        throw new BusinessException("appId异常");
    }

}

然后我们看tomcat localhost log:

16-Aug-2021 11:53:41.756 严重 [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.StandardContext.filterStart 启动过滤器异常
	javax.naming.NameNotFoundException: 名称[com.video.manager.component.GatewayFilter/applyService]未在此上下文中绑定。找不到[com.video.manager.component.GatewayFilter]

很显然,是我们filter里不能注入bean,这是由于filter的优先级比较高,在web容器启动时就开始加载filter,此时我们写的bean都还没注入到容器,肯定是找不到的,所以后来改成 步骤二 里的实现。之前也遇到过这个问题,记当时记住了,时间长了就忘了,所以这次记录下。这里注入bean也有其他实现方式,有兴趣可以自己实现下。

其实实现网关接口管理也可以使用注解方式实现,不过个人觉得不适合,于是选择了filter,注解的话需要把每个需要统计的接口都要加上注解,不灵活,filter的话可以把统计的接口放到apollo上,动态更新,更灵活。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot中添加Filter有多种方式。一种方式是通过实现`javax.servlet.Filter`接口,并将其声明为一个Bean交由Spring容器管理。可以使用`@WebFilter`注解来简化该过程。另一种方式是使用`DelegatingFilterProxyRegistrationBean`来注册Filter。首先,我们需要在一个@Configuration类中创建一个名为`FilterConfig`的Bean,然后在该Bean中使用`DelegatingFilterProxyRegistrationBean`来注册我们的Filter。可以使用该Bean的`addUrlPatterns`方法指定过滤规则。这样,我们就可以通过配置类来注册Filter并指定过滤规则。还可以直接在配置类中使用@Bean注解来创建Filter,并在其中实现具体的过滤逻辑。然后,我们可以使用`DelegatingFilterProxyRegistrationBean`来注册已经在容器中注册的Filter。以上是在Spring Boot中添加Filter的几种常用方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [SpringBoot实现过滤器Filter的三种方式](https://blog.csdn.net/huanby/article/details/124708492)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [SpringBoot - 配置 Filter 的几种方式](https://blog.csdn.net/qiaohao0206/article/details/125658982)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值