Spring: how to pass objects from filters to controllers

前端 未结 5 1288
被撕碎了的回忆
被撕碎了的回忆 2021-01-02 05:19

I\'m trying to add a Filter that creates an object that is then to be used inside a controller in a Spring Boot application.

The idea is to use the Filter as a \"cen

相关标签:
5条回答
  • 2021-01-02 05:34

    you can use ServletRequest.setAttribute(String name, Object o);

    for example

    @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() {
    
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-02 05:34

    I dont know actually what is the scenario but If you really want to create an object in a filter and then use it somewhere in the code then you may use ThreadLocal class to do so.

    To get know how this work see the most voted answer from that question Purpose of ThreadLocal?

    In general using ThreadLocal you will be able to create a class that can store objects available ONLY for the current thread.

    Sometimes for optimization reasons the same thread can be used to serve subsequent request as well so it will be nice to clean the threadLocal value after the request is processed.

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

    in the filter

    MyObjectStorage.getThreadLocal().set(myObject);
    

    and in the Controller

    MyObjectStorage.getThreadLocal().get();
    

    Instead of filter you can use also @ControllerAdvice and pass objects to specified Controllers by using model.

    @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";
       }
    }
    
    0 讨论(0)
  • 2021-01-02 05:36

    One way I've seen this done is to wrap the HttpServletRequest object with your own implementation that is aware of the original and your temporary object. The advantage to this is that it's limited to the request scope and isn't stored in the thread or session. So something like this:

    public class MyServletRequest extends HttpServletRequestWrapper {
      private MyObject obj;
      public MyServletRequest(HttpServletRequest request){
        super(request);
      }
      //set your object etc
    }
    

    Then in your servlet:

    public void doGet(HttpServletRequest req, HttpServletResponse resp){
       MyServletRequest myRequest = (MyServletRequest)req;
       //now you can access your custom objects
    }
    
    0 讨论(0)
  • 2021-01-02 05:42

    Why Don't you use a Bean with the @Scope('request')

    @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;
    }
    

    and then you can Autowireed this bean in both filter and controller to do setting and getting of data.

    lifecycle of this UserInfo bean is only exisits within the request so once the http request is done then it terminates the instance as well

    0 讨论(0)
  • 2021-01-02 05:45

    An addition to wcong's answer. Since Spring 4.3 after setting the attribute by using request.setAttribute(passKey, passValue);, you can access the attribute in your controller by simply annotating it with @RequestAttribute.

    ex.

    @RequestMapping("/")
    public String index(@RequestAttribute passKey) {
        return (String) passKey;
    }
    
    0 讨论(0)
提交回复
热议问题