I'm playing with spring interceptors in last few days and want to catch and handle specific requests through interceptor. What I want to do is to intercept each request before it is processed by specific controller, check whether request contains specific parameters or not. If yes, do some stuff and than sign that stuff to controller which maps that request.
At the end I managed to do that, but when I execute multiple requests at once, with different param values, only param value from last request is assigned to each of controller handler, even every controller should have params which are contained within the request.
Example (executed at the same time):
http://domain.com/controller/method?param=xfg
http://domain.com/controller/method?param=mtc
http://domain.com/controller/method?param=abc
in responses from each request, I get abc! (sometimes I get xfg and abc, or mtc and abc, but never all three of them). When I execute these requests with timeout where every request have time to complete before next one is called, it is working fine.
Does anyone know how to handle this?
Thanks
UPDATED:
public class OLMyInterceptor extends HandlerInterceptorAdapter {
static Logger LOG = Logger.getLogger(OLAuthentificationInterceptor.class);
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String, Object> activeParamsMap = request.getParameterMap();
for(Entry<String, Object> param : activeParamsMap.entrySet()) {
if(param.getKey().startsWith("aP_")) {
activeParams.put(param.getKey().substring(3), param.getValue());
}
}
((MainController) handler).setParams(activeParams);
return true;
}
}
There you have code sample. Every controller of mine extends MainController, that's why I cast handler to MainController, which have setParams method. Every other controller use params in different way.
You must invoke a controller handler method with params, not setter which changes controller state.
The controller must be stateless or thread-safe. When you change state you do not have a guarantee when the setter applies changes - before handlers invoked in another thread, or after. Or another thread invokes setter with other params and previous thread invokes handler method for new params.
Related
I have written a interceptor to make some changes before service call in my spring boot rest service.
Added picture to show my code how I written preHandle method.
In the picture, I want to bring the "orginationTaskServerMockEnabled = true" value which is in
handler -> bean-> mHandler -> dashboardConfig-> originationTaskServerMockEnabled
I tried by it doesnt, is it possible to bring the values from HanlderMethod. If so please help me.
It is not possible to access the handler arguments in the interceptor's preHandle. It is called before the actual invocation of the handler method. The resolution of actual argument types is done during its invocation, so during the execution of preHandle, the argument's value are not resolved yet (but are described by Object handler argument). Only HttpServletRequest and HttpServletResponse are known during the execution so, if the data is attached to the request, you can grab it from there.
Alternatively, you can use an aspect and wrap it around your controller method. From there, you can grab the method arguments then perform your preprocessing.
#Around("execution (* com.pck.controllers.*.*(..)) && #annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object beforeHandler(ProceedingJoinPoint p){
Object args[] = joinpoint.getArgs();
return joinpoint.proceed();
}
I know that in JavaEE, filters can intercept any request to a servlet. But Interceptors in Spring MVC are not exactly the same. If you look at the diagram below, you will see that Interceptors come after Dispatcher Servlet.
Let me give you an example before I ask my question.
I have a controller, which has 2 methods in it that are mapped to two different requests. One accepts GET requests and other accepts POST requests. Now if I add an interceptor in my web application, that interceptor will sit before Controller. Meaning that before controller method is hit, first a request will hit my interceptor's preHandle method.
Now say that in my app, two controllers methods look like this:
#Controller
public class myController{
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test1(){
return "abc";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String test1(){
return "xyz";
}
And lets say I have a simple interceptor like this:
public class URLInterceptors extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("REQUESTED SERVLET PATH IS: " + request.getServletPath());
return true;
}
}
Now, if I make a GET request to /test, my interceptor is hit and it prints the servlet path, but when I make a GET request to /login, I know it will fail because my method that handles /login mapping accepts only POST requests, however before it throws '405 Request method 'GET' not supported' error, it should at least hit first my interceptor? It doesn't. I I don't want to change POST to GET. So the question is why?
Part of this is explained in
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
In summary, the DispatcherServlet attempts to find an appropriate handler for your request by using a HandlerMapping (see your graphic). These handlers are actually adapters that wrap the actual handler method (a #RequestMapping annotated method in this case) with the interceptors you've registered. If this handler is found, then the DispatcherServlet can proceed, invoke interceptors, and, if required, invoke your handler method.
In your case, because your #RequestMapping is restricted to POST requests and your request is a GET, the DispatcherServlet fails to find an appropriate handler and therefore returns an error before it's had a chance to invoke any interceptors.
Note that the javadoc states
A HandlerInterceptor gets called before the appropriate HandlerAdapter
triggers the execution of the handler itself.
but your DispatcherServlet never found a handler to begin with.
You might want to consider using a Servlet Filter instead.
I am writing a Servlet that retrieves request parameters but needs to use them in the init method. Since the init method would be called before the doGet method and since the init method does not have a HttpServletRequest object as an argument, I don't know how to get the request parameters.
public class OpenIdServlet extends HttpServlet
{
...
...
private OpenIdManager manager;
#Override
public void init() throws ServletException
{
super.init();
manager = new OpenIdManager();
manager.setRealm("http://localhost:8080/OpenIDSample");
manager.setReturnTo("http://localhost:8080/OpenIDSample/openid"); //I need to append the value of a request parameter here...
}
...
...
}
So the question is: is there any way I can get HttpServletRequest parameters in the init() method of a servlet? If no what other better approach can one use to solve this problem? Thanks.
The init is called once on startup. So you have to live with a partial returnTo, and on request handling (doGet/doPost) complete it with the request parameters.
In fact the manager seems to be request dependent and hence should be created in the request - never as field. As there might be several requests. Maybe persisting as session attribute.
Your question doesn't make sense. There is no request when the init() method is called. It is called during container initialisation.
Do you mean initial parameter? They are available via the ServletContext provided as an argument to init().
I would like to invoke some custom method when a REST call has finished, looking up annotations on the originating method and the generated response.
I know you can use the PostProcessInterceptor or MessageBodyWriterInterceptor for this task but they do not get invoked in case of an exception.
My current solution is such that every method throws a special exception which is then handled by a custom ExceptionMapper, but there I have no information about the original request and where it came from.
Is there a global wide handler you can bind to in order to get the information about the original request in case of an exception?
And yes I know about this question: RestEasy Post Process Interceptor chain not traversed when response created by ExceptionMapper
To answer my own question.
One can inject the original request into the ExceptionMapper and react or perform a custom action accordingly.
#Provider
public class MyExceptionMapper implements ExceptionMapper<Throwable> {
#Context
private HttpServletRequest request;
#Override
public Response toResponse(Throwable exception)
{
// trigger event
triggerOnExceptionEvent(request, exception);
}
...
}
I need to grab a certain custom HTTP header value from every request and put it in WebSession so that it will be available on any WebPage later on. (I believe the Wicket way to do this is to have a custom class extending WebSession that has appropriate accessors.)
My question is, what kind of Filter (or other mechanism) I need to be able to both intercept the header and access the WebSession for storing the value?
I tried to do this with a normal Java EE Filter, using
CustomSession session = (CustomSession) AuthenticatedWebSession.get();
But (perhaps not surprisingly), that yields:
java.lang.IllegalStateException:
you can only locate or create sessions in the context of a request cycle
Should I perhaps extend WicketFilter and do it there (can I access the session at that point?), or is something even more complicated required?
Of course, please point it out if I'm doing something completely wrong; I'm new to Wicket.
I'd guess you need to implement a custom WebRequestCycle:
public class CustomRequestCycle extends WebRequestCycle{
public CustomRequestCycle(WebApplication application,
WebRequest request,
Response response){
super(application, request, response);
String headerValue = request.getHttpServletRequest().getHeader("foo");
((MyCustomSession)Session.get()).setFoo(headerValue);
}
}
And in your WebApplication class you register the custom RequestCycle like this:
public class MyApp extends WebApplication{
#Override
public RequestCycle newRequestCycle(Request request, Response response){
return new CustomRequestCycle(this, (WebRequest) request, response);
}
}
Reference:
Request cycle and request cycle
processor