difference between Spring mvc redirect and general jsp name return - spring

Please consider these code snippets
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("redirect:DummyRedirectPage.htm");
}
and
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception {
return new ModelAndView("somejsp");
}
Can anyone tell me the difference between the two? In both the cases the handler method is navigating the flow to a view page.

With the first one user will receive HTTP 302 response to redirect into DummyRedirectPage.htm. If the handler was mapped to a POST method, this will force user to perform GET to DummryRedierctPage.htm
On the second one your view resolver will resolve "somejsp" into an actual view. No HTTP 302 response is given to user.
Please read about PRG (Post Redirect Get) design pattern to find out why this matters.

Related

Spring - Changing Order of Global Error handler and Filter

I have a filter like:
#Component
#Order(8)
public class LogReqFilter extends OncePerRequestFilter
{
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException
{...}
}
it basically logs all requests and responses. When there is a 400 error however the response is blank. There is a global exception handler that replaces the body with the custom error:
#RestControllerAdvice
public class GlobalExceptHandler extends ResponseEntityExceptionHandler {
#Override
#ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleArgNotValid(MethodArgumentNotValidException ex
, HttpHeaders headers, HttpStatus status, WebRequest request) {...}
}
I noticed that the Global Exception handler is called after the filter and I think that this is why the response is blank in the filter. Is there a way to have the filter called after the Global Exception Handler?
Edited:
TLDR
No You can't change the order as per the OP Title because your GlobalError Handler is always in the layer that holds the ControllerAdvices and that is always between the RequestFilter layer and the Controller.
Long Version
You are somewhat right.
i refer you to this answer: https://stackoverflow.com/a/17716298/405749
expanding on this:
be aware that before and after depends from which you are looking from, ie.
inbound (before it reaches your controller code) OR
outbound (after the controller is done)
now you can plug in different components on this path, e.g. here RequestFilter and Controller Advice
depending on the method you implement, it gets called only on the inbound or outbound track or both, here:
doFilterInternal() is called inbound. Only if you call filterChain.doFilter(request, response); the request continues on the inbound track otherwise it stops here and the response is returned with whatever is already in its output stream or will be added by this filter or filters still be encountered on the way out
this is the call sequence assuming we only have this filter and advice
'inbound'-methods from request filters
'inbound'-methods from controller advice(s)
'outbound'-methods from controller advice(s)
'outbound'-methods from request filters
Now, the handleArgNotValid() only gets called in case such an exception is thrown and potentially adds content to the Response-Output stream. Your example doesnt show if you return an object here or not, but i guess from your OP that you dont. and as a consequence the output stream is empty.
Plz also note, that there is no easy way to dump/look into the output stream unless you wrap it, but that's another topic.

Spring MVC redirect to page with custom parameter when session expired

I can not find any solutions for Spring to redirect to page together with parameters when session is timed out. I need to redirect to login page with error like "Session expired". I have tried filter and method session.isNew(). But it does not work since when request reaches login page it always already has session. Also HttpSessionEvent handler does not work because does not allow to access to request attributes and redirect to page.
The easiest way would be to create an Interceptor that adds the Refresh header to every response with a time just after session expiry.
public class RefreshInterceptor extends HandlerInterceptorAdapter {
#Override
public void postHandle (
HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView
) throws Exception {
//if session != null and user is authenticated then...
response.setIntHeader("Refresh", figureOutWhenSessionExpires() + A_SMALL_DELAY );
super.postHandle(request, response, handler, modelAndView);
}
}

Building a façade with spring which calls another server and returns its response

For an application I need to create a security façade in Spring 4.x.
This thiny layer must accepts any request from our mobile application and execute a security check for the provided token (with openId and Oauth).
Upon a successful validation, the request needs to be forwarded to the backend application, which does not need to be aware of the security token mechanism.
Thus, the flow will be something like this:
security_facade_url/path/of/the/request
With a header that indicates the backend to invoke upon successful validation of the token
Upon successful validation the security façade sends a request to the backend URL
backend_application_url/path/of/the/request
The façade must not have a controller which maps to any possible path of the request, but must call the request on the correct backend server, based on a value in the header of the request. Then return this response to the user.
What I have so far is an implementation of the HandlerInterceptor. This interceptor works, however, I am not really happy with the way I need to avoid the afterCompletion by throwing an exception in the postHandle method.
If I do not throw an error, the default error page is appended to the correct response in the afterCompletion step.
This is my code so far:
public class RequestProcessingInterceptor implements HandlerInterceptor {
private final Logger log = LoggerFactory.getLogger(RequestProcessingInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
log.info("Doing some security stuff now ...");
log.warn("... security ok ... since I am not really checking stuff");
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
log.info("Forwarding request and sending that info back ...");
ClientConfig config = new DefaultClientConfig();
Client client = Client.create(config);
WebResource service = client.resource(UriBuilder.fromUri("http://localhost:8080").build());
response.setContentType("application/json");
response.getWriter().write(service.path(modelAndView.getModel().get("path").toString()).accept("application/json").get(String.class));
response.setStatus(200);
throw new Exception("Need to avoid the execution of the afterCompletion. Only way to do so is by throwing an exception...");
}
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
Is there a more proper way to intervene with the Spring livecycle or obtain the behaviour as described above?
Found a better solution. For what I need, I do not need to manipulate the results in an interceptor.
A much cleaner way is to define a Controller which maps with the request methods.
#RequestMapping(method = {RequestMethod.GET, RequestMethod.PUT, RequestMethod.POST})
public void handleRequest(HttpServletRequest request, HttpServletResponse response) { // code omitted }
You should not try to avoid the call to afterCompletion. Just implement an empty method and let SpringFramework call it.
Provided your controller returns null indicating that no view has to be called, it should work with a smoother Spring integration.
But I cannot understand why you use Spring MVC here. As you only interact with low level HttpServletRequest and HttpServletResponse, you could as well use :
a dedicated servlet in charge to relay the request and response to the backend and write the returned value in the response
a filter that would do the security stuff before passing request to filter chain

Spring #Validated Causing HTTP 400

When I add the #validate annotaion to a method signature in my controller, I get a HTTP 400 with the description, "The request sent by the client was syntactically incorrect ().". Does anyone have an idea why?
Good Code
public ModelAndView startAccountSubmittal(
AccountCredential accountCred, HttpServletResponse response)
throws MessagingException {
Bad Code
public ModelAndView startAccountSubmittal(
#Validated(value={AccountStates.Submitted.class})
AccountCredential accountCred,
HttpServletResponse response, BindingResult result)
throws MessagingException {
Thanks in advance,
Joe
The uncaught exception I had configured was not catching the error. I added an exception handler to the controller and I was able to get the details. I had a few extra fields it was trying to validate, which contained nulls, but required values. This what caused the HTTP 400. Turning on the exception handler helped get the exception and stacktrace. I modified the code and added extra groups, then added those new groups to the object and controller. It works as planned.

How to add Precall method in Spring MVC Controller

I have one requirement to fulfill.
Actually when ever user Login into my application , i will save the logged in user name in session attribute like .
session.setAttribute("LOGIN_USER", userName);
So that, if user tries to access my method links directly with out coming from Login page i can check in controller method whether this session has the specific attributive value as below and i can restrict user to access that page and redirect him to login page.
if(request.getSession(false).getAttribute("LOGIN_USER")==null)
//redirect to login page
Now,my requirement is if i have 50 methods in controller i can't add this condition in each method.I think there is a way we can add some sort of filters or any method in controller class like ex #preExecuteMethod to first execute this method and proceed for the actual call if success.
Yes, you can use a HandlerInterceptor for this. See the docs here and here.
Interceptor is the solution. It has methods preHandler which will be called before each request. You can hook into each HTTPServletRequest object and do the nnecessary stuff.
here is a sample code:
#Component
public class AuthCodeInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// set few parameters to handle ajax request from different host
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.addHeader("Access-Control-Max-Age", "1000");
response.addHeader("Access-Control-Allow-Headers", "Content-Type");
response.addHeader("Cache-Control", "private");
String reqUri = request.getRequestURI();
String serviceName = reqUri.substring(reqUri.lastIndexOf("/") + 1,
reqUri.length());
if(request.getSession(false).getAttribute("LOGIN_USER")==null) {
//redirect to login page
}
return super.preHandle(request, response, handler);
}
#Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
}
Maybe you could use an AOP #Before aspect giving the pointcut to the methods in your handler class ? See the reference here or you could create a normal filter via the delegatingFilterProxy explained here . I think overall #skaffman gives a better idea .

Resources