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
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() {
}
}
}
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";
}
}
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
}
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
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;
}