Spring:如何将对象从过滤器传递给控制器

时间:2016-02-16 22:56:06

标签: spring spring-boot

我试图添加一个Filter,它创建一个对象,然后在Spring Boot应用程序的控制器中使用。

我们的想法是将过滤器用作"集中式"此对象的生成器 - 这是特定于请求的,仅在控制器中有用。 我尝试使用HttpServletRequest request.getSession().setAttribute方法:我可以在控制器中访问我的对象,但随后它会(明确地)添加到会话中。

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

5 个答案:

答案 0 :(得分:7)

你可以使用 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() {

        }
    }
}

答案 1 :(得分:5)

为什么不使用带有@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请求完成,它就会终止实例

答案 2 :(得分:2)

我实际上并不知道什么是场景但是如果你真的想在过滤器中创建一个对象,然后在代码中的某个地方使用它,那么你可以使用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";
   }
}

答案 3 :(得分:2)

wcong答案的补充。 从Spring 4.3开始,在使用request.setAttribute(passKey, passValue);设置属性之后,您可以通过用@RequestAttribute对其进行注释来访问控制器中的属性。

例如。

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

答案 4 :(得分:0)

我看到这样做的一种方法是使用您自己的实现来包装HttpServletRequest对象,该实现知道原始对象和临时对象。这样做的好处是它仅限于请求范围,并且不存储在线程或会话中。所以像这样:

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

然后在你的servlet中:

public void doGet(HttpServletRequest req, HttpServletResponse resp){
   MyServletRequest myRequest = (MyServletRequest)req;
   //now you can access your custom objects
}