【问题标题】:Spring: how to pass objects from filters to controllersSpring:如何将对象从过滤器传递到控制器
【发布时间】:2016-05-28 10:40:36
【问题描述】:

我正在尝试添加一个过滤器,该过滤器创建一个对象,然后在 Spring Boot 应用程序的控制器中使用该对象。

这个想法是使用过滤器作为这个对象的“集中”生成器——它是特定于请求的并且仅在控制器中有用。 我尝试使用HttpServletRequest request.getSession().setAttribute 方法:我可以在控制器中访问我的对象,但随后它将(显然)添加到会话中。

过滤器是这样做的正确方法吗?如果是,我可以在哪里保留过滤器生成的临时对象以供控制器使用?

【问题讨论】:

    标签: spring spring-boot


    【解决方案1】:

    为什么不使用带有@Scope('request') 的Bean

    @Component
    @Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS)
    class UserInfo {
       public String getPassword() {
          return password;
       }
    
       public void setPassword(String password) {
          this.password = password;
       }
    
       private String password;
    }
    

    然后你可以在过滤器和控制器中Autowireed这个bean 来设置和获取数据。

    这个UserInfo bean 的生命周期只存在于请求中,所以一旦 http 请求完成,它也会终止实例

    【讨论】:

    • 能否请您发布完整的示例?
    • 最佳答案!最优雅。
    • 这是在 Spring 或任何 DI 框架(如 CDI)的上下文中最合适的答案。
    • 不错的答案!请注意,引入了一个新的组合注释 @RequestScope,其作用与 @Scope(value="request", proxyMode= ScopedProxyMode.TARGET_CLASS) 相同
    • 如果我们将用户信息存储在此组件中,其他用户是否有可能从另一个请求中获取数据?
    【解决方案2】:

    你可以使用ServletRequest.setAttribute(String name, Object o);

    例如

    @RestController
    @EnableAutoConfiguration
    public class App {
    
        @RequestMapping("/")
        public String index(HttpServletRequest httpServletRequest) {
            return (String) httpServletRequest.getAttribute(MyFilter.passKey);
        }
    
        public static void main(String[] args) {
            SpringApplication.run(App.class, args);
        }
    
        @Component
        public static class MyFilter implements Filter {
    
            public static String passKey = "passKey";
    
            private static String passValue = "hello world";
    
            @Override
            public void init(FilterConfig filterConfig) throws ServletException {
    
            }
    
            @Override
            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                    throws IOException, ServletException {
                request.setAttribute(passKey, passValue);
                chain.doFilter(request, response);
            }
    
            @Override
            public void destroy() {
    
            }
        }
    }
    

    【讨论】:

    • 它能否同时处理多个(数百个)请求而不冲突属性值?
    【解决方案3】:

    我不知道实际情况是什么,但如果您真的想在过滤器中创建一个对象,然后在代码中的某处使用它,那么您可以使用ThreadLocal 类来执行此操作。

    要了解这项工作的原理,请查看该问题的投票最多的答案Purpose of ThreadLocal?

    通常使用ThreadLocal,您将能够创建一个可以存储仅可用于当前线程的对象的类。

    有时出于优化原因,同一线程也可用于处理后续请求,因此在处理请求后清理 threadLocal 值会很好。

    class MyObjectStorage {
      static private ThreadLocal threadLocal = new ThreadLocal<MyObject>();
    
      static ThreadLocal<MyObject> getThreadLocal() {
        return threadLocal;
      }
    }
    

    在过滤器中

    MyObjectStorage.getThreadLocal().set(myObject);
    

    在控制器中

    MyObjectStorage.getThreadLocal().get();
    

    您也可以使用@ControllerAdvice 来代替过滤器,并使用模型将对象传递给指定的控制器。

    @ControllerAdvice(assignableTypes={MyController.class})
    class AddMyObjectAdvice {
    
        // if you need request parameters
        private @Inject HttpServletRequest request; 
    
        @ModelAttribute
        public void addAttributes(Model model) {
            model.addAttribute("myObject", myObject);
        }
    }
    
    
    @Controller
    public class MyController{
    
       @RequestMapping(value = "/anyMethod", method = RequestMethod.POST)
       public String anyMethod(Model model) {
          MyObjecte myObject = model.getAttribute("myObject");
    
          return "result";
       }
    }
    

    【讨论】:

    【解决方案4】:

    对 wcong 的回答的补充。 由于 Spring 4.3 在使用 request.setAttribute(passKey, passValue); 设置属性后,您可以通过简单地使用 @RequestAttribute 注释来访问控制器中的属性。

    例如

    @RequestMapping("/")
    public String index(@RequestAttribute passKey) {
        return (String) passKey;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-12
      • 2013-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-21
      • 2013-08-30
      • 2015-11-11
      相关资源
      最近更新 更多