当前位置: 首页 > 知识库问答 >
问题:

Spring过滤器:获取servlet url模式

臧曜瑞
2023-03-14

假设我已经定义了这些RESTendpoint:

@RequestMapping(path = "/user")
@RestController
public class ConfigUserController {

    [...]
    
    @GetMapping(path = "/variables/")
    public ResponseEntity<List<Variable>> getAllVariables(...)
        [...]
    }
    
    @GetMapping(path = "/variables/{name}")
    public ResponseEntity<Variable> getVariableByName(...)
        [...]
    }
    
    @PutMapping(path = "/variables/{name}/{value}")
    public ResponseEntity<Variable> setVariableByName(...)
        [...]
    }
}

我定义了两个过滤器(日志记录和授权),在这些过滤器中,我想获得与当前请求匹配的url模式。使用上述示例:

  • 如果请求是一个GET到 /variables,我需要"/变量"
  • 如果请求是一个GET到 /variables/myfancyname,我需要"/变量/{name}"
  • 如果请求是一个PUT到 /variables/myfancyname/myvalue,我需要"/变量/{名称}/{值}"

基本上,我需要的是在我的过滤器的doFilter(ServletRequest-request-request,ServletResponse-response,FilterChain-chain)方法中获得映射注释中定义的路径。

理想情况下,我希望能够访问我的过滤器中的url模式值,如下所示:

@Component
@Order(3)
public class MyAuthorizationRequestFilter extends GenericFilterBean {
    [...]
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // here I get the value
        String urlPattern = request.useSomeMethod().toGetUrlPattern();
        [...]
        boolean auth = false;
        // here I do stuff
        [...]
        // finally let's see if the user is authorized
        if (auth) {
            chain.doFilter(request, responde);
        } else {
            throw SomeAuthorizationError();
        }
    }
    [...]
}

我一直在寻找,但我找不到一个可行的解决方案。

如果可能的话,我宁愿不扫描集合或web.xml文件(我没有),也不使用反射,因为每次触发过滤器时都会执行代码,我不想影响性能。

欢迎链接或建议。

编辑:添加详细信息,添加过滤器示例cose

共有2个答案

慎志国
2023-03-14

过滤器在请求到达DispatcherServlet之前拦截请求,使其成为粗粒度任务的理想选择,例如:

  • 身份验证

注意*在尝试调用getAttribute之前,先执行doFilter

您的控制器

@RequestMapping(path = "/user")
@RestController
public class ConfigUserController {

    @GetMapping(path = "/variables/")
    public ResponseEntity<List<Variable>> getAllVariables() {
        return null;
    }

    @GetMapping(path = "/variables/{name}")
    public ResponseEntity<Variable> getVariableByName(@PathVariable("name") String name) {
        return new ResponseEntity<Variable>(new Variable(name), HttpStatus.OK);
    }

    @PutMapping(path = "/variables/{name}/{value}")
    public ResponseEntity<Variable> setVariableByName() {
        return null;
    }
}

定制过滤器

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO
        try {
            chain.doFilter(request, response);
        } catch (Exception e) {
        } finally {
            String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
            System.out.println("Request template is, " + pattern);
        }
    }

}

订单号:

 Request template is, /user/variables/{name}

HandlerIntercepors拦截DispatcherServlet和我们的控制器之间的请求。这是在Spring MVC框架内完成的,它提供了对处理程序和ModelAndView对象的访问。

自定义拦截器

@Component
public class LoggerInterceptor implements HandlerInterceptor {

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

    }

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

    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        String path = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        System.out.println("path : " + path);
        return true;
    }}

向InterceptorRegistry注册

@Component
public class CustomServiceInterceptorAppConfig implements WebMvcConfigurer {
   @Autowired
   LoggerInterceptor loggerInterceptor;

   @Override
   public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(loggerInterceptor);
   }
}

单例作用域并设置为预实例化(默认)的Bean是在创建容器时创建的。这是一个一次性过程,您不必担心性能。

您可以预扫描所有@RequestMapping、@GetMapping、@PostMApping等。。注释,保留它,然后在过滤器中匹配模式以获得所需的结果。

这是样品

@Configuration
public class Config {

    @Bean
    public List<String> getPatterns() throws ClassNotFoundException {

        List<String> str = new ArrayList<String>();
        Class clazz = Class.forName("com.example.demo.controller.ConfigUserController"); // or list of controllers,
                                                                                            // //you can iterate that
                                                                                            // list
        for (Method method : clazz.getMethods()) {
            for (Annotation annotation : method.getDeclaredAnnotations()) {
                if (annotation.toString().contains("GetMapping")) {
                    str.add(annotation.toString());
                    System.out.println("Annotation is..." + annotation.toString());
                }
                if (annotation.toString().contains("PutMapping")) {
                    str.add(annotation.toString());
                    System.out.println("Annotation is..." + annotation.toString());
                }
                if (annotation.toString().contains("PostMapping")) {
                    str.add(annotation.toString());
                    System.out.println("Annotation is..." + annotation.toString());
                }
            }
        }

        return str;

    }

定制过滤器

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CustomFilter implements Filter {
    @Autowired
    Config con;
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // TODO
        try {
            //filter match the pattern to get the desired result
            System.out.println(con.getPatterns());
        } catch (ClassNotFoundException e) {
            
        }
        chain.doFilter(request, response);
    }
柯镜
2023-03-14

更新答案以使用GenericFilterBean。根据提出的问题进行筛选。可以通过添加finally子句来实现这一点。这是必需的,因为您需要执行链。doFilter(请求,响应)首先调用请求。getAttribute,因为该属性直到请求生命周期的后期才设置。因此,如果您试图基于传入的uri模板执行某些操作,那么在这里子类化GenericFilterBean可能不是正确的选择,因为您需要调用chain。先进行doFilter。

 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        try {
            //Do something
            chain.doFilter(request, response);
        } finally {
         String pathTemplate = (String) 
request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
         System.out.println("Incoming Request path Template from Generic Filter : " + pathTemplate);
}


}

替代选项:

假设您在这里使用的是Spring Web。您可以定义一个HandlerInterceptor并将其注册到Interceptor注册表

@Component
public class LogPathTemplateInterceptor
        implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        String pathTemplate = (String)request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
        System.out.println("Incoming Request path Template : " + pathTemplate);
        return true;
    }
}

定义完后,向InterceptorRegistry注册它。查看如何将路径模式添加到拦截器。

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private LogPathTemplateInterceptor logInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(logInterceptor)
                .addPathPatterns("/variables/**");
    }
}

这应该记录请求模板路径,而不是带有变量的路径。

 类似资料:
  • 问题内容: 我对创建一个可以接受金额,ISO 4217货币代码和小数大小并以该格式返回金额的过滤器感兴趣。我注意到AngularJS在中,但是我对Angular比较陌生,不知道是否可以使用它? 问题答案: 货币模式和符号就是这样。它确定如何显示数字。它将不会从XXX转换为XXX。您将必须根据当前的转换率进行转换。 至于使用内置货币格式,有多种方法:在模板中,在代码中。 在模板中: 在代码中: 在这

  • 问题内容: 我定义了一个,并且具有带有Spring注释的Java类。 我想将Bean 放入我的,因此尝试了以下操作: 但是它总是返回。我怎样才能得到一个Spring bean? 问题答案: 尝试: 你的bean在应用程序上下文中的名称/标识在哪里。甚至更好: 还可以看看GenericFilterBean及其子类。

  • 主要内容:实现,Person.java,Criteria.java,CriteriaMale.java,CriteriaFemale.java,CriteriaSingle.java,AndCriteria.java,OrCriteria.java,CriteriaPatternDemo.java过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型

  • 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。 实现 我们将创建一个 Person 对象、Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表。CriteriaP

  • 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern)是一种设计模式,这种模式允许开发人员使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。这种类型的设计模式属于结构型模式,它结合多个标准来获得单一标准。 实现 我们将创建一个 Person 对象、Criteria 接口和实现了该接口的实体类,来过滤 Person 对象的列表。CriteriaP

  • 我正在处理一个安全过滤器,它需要根据path变量的值做一些检查。我试着这样做: 但映射始终为空,因此我的筛选器的优先级似乎高于在请求中填充属性的。 我已尝试添加以下配置: 这没有帮助,筛选器是在调用之前执行的。 在我的安全过滤器中,我获取Auth头,解密它,从中获取并将它与路径var值进行比较。如果这些ID不匹配,我返回403。 我想知道是否有可能覆盖这两个动作的顺序。或者,也许,有其他的方法来检