We are using Spring 2.5.x and we are doing this: Posting a form, responding to this in the controller method where we generate some data. Now, at the end we are doing a redirect to another page. We need to access the data generated in the post request handler method.
From the post handler, declared to return a ModelAndView:
Map<String, String> map = new HashMap<String, String>();
map.put("myKey", "someValue");
ModelAndView mav = new ModelAndView(new RedirectView("/my/view", true, true, false), map);
return mav;
In the get method handler we want to access these data and use them in the view for this method. How do we access these values? The modelmap that I inject to this method is empty. And only null values are shown in the view if I try to use ${myKey}
We are using Spring 2.5.x, so I can't use RequestAttributes etc.
FlashMap which you would get with RequestContextUtils. was added in Spring 3.1. As far as I know, you'll therefore need to implement your own flash attributes mechanism. You can use a servlet Filter as explained in this blog post. Or, very basically, add stuff to the HttpSession and clear them in a future request.
Save the map data in session scope before executing your redirect. Then in your page, consume the data from the map using JSTL. At the bottom of your page, remove this map from session scope using <c:remove>.
In your java class:
Map<String, String> map = new HashMap<String, String>();
map.put("myKey", "someValue");
session.addAttribute("myMap", map);
//the rest of your logic...
In your JSP/JSTL code:
Map.myKey value: ${map.myKey}
<!-- at the bottom of the JSP, remove the variable from session -->
<c:remove var="myMap" scope="session" />
Related
I have a spring rest controller and I want to properly receive a form-data from my UI. Do you know any other way of getting form-data besides of my proposal?
I have managed to get the data using #RequestPart("fields-name") but its not optimal since I need to get the form-data and send it as it is to another rest controller.
MyResponse addAttachment(#RequestParam("file") MultipartFile file, #RequestParam("note") String note);
In the end I want the flow to look like this:
|UI|--(form-data)---> |Java-Spring A| ---(form-data)----> |Java-Spring B|--(file-from-form)--> |DB|
currently it looks like that:
In spring A: myResponse addAttachment(#ModelAttribute AttachmentForm form)
In spring B: myResponse addAttachment(#ModelAttribute MultiValueMap<String, Object> form)
From A->B I do the following:
MultiValueMap<String, Object> valueMap = new LinkedMultiValueMap<>();
valueMap.add("note", form.getNote());
valueMap.add("file_name", file.getOriginalFilename()); //Send the file as bytes array
valueMap.add("files", new ByteArrayResource(file.getBytes()));
resttemplate.sendhttpcall(valueMap);// helper function to send between A->B
After sending the form data ( as a model object AttachmentForm) I parse it before sending it from A to B. one step after restTemplate.exchange it gets to Spring B and I get the following exception (in my Expception controller class):
"java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.util.MultiValueMap"
Thanks
The source code for Spring OAuth2's AuthorizationEndpoint contains two redundant #RequestMapping annotations for the same /oauth/authorize endpoint. One of them specifies the POST method, while the other does not specify a method.
How are the two #RequestMapping annotations interpreted? Does the one that specifies POST exclusively handle all POST /oauth/authorize requests, and does the one that does not specify a method exclusively handle any non-POST requests to /oauth/authorize? Or do both methods overlap, with both methods being called for certain requests?
This is probably a Spring MVC question, though the source code on GitHub uses Spring MVC to define what is Spring OAuth2.
Though the complete source code is available on GitHub at the link that the top of this OP, the headers for the two relevant methods are summarized here as follows:
#RequestMapping(value = "/oauth/authorize")
public ModelAndView authorize(Map<String, Object> model, #RequestParam Map<String, String> parameters,
SessionStatus sessionStatus, Principal principal) {
//other stuff
}
#RequestMapping(value = "/oauth/authorize", method = RequestMethod.POST, params = OAuth2Utils.USER_OAUTH_APPROVAL)
public View approveOrDeny(#RequestParam Map<String, String> approvalParameters, Map<String, ?> model,
SessionStatus sessionStatus, Principal principal) {
//other stuff
}
This is already explained in the official documentation: if you provide the values for the method field, they'll be used to narrow down the mapping. In other words: Spring MVC will use these hints to find the most precise match for each request.
It's also easy to build a simple proof-of-concept application that demonstrates it in practice:
#RequestMapping("/foo")
#ResponseBody
public String hello() {
return "hello, default";
}
#RequestMapping(value="/foo", method = RequestMethod.GET)
#ResponseBody
public String helloGet() {
return "hello, GET";
}
Hitting /foo with a GET request, for instance using Postman, will return "hello, GET". All other supported HTTP methods (POST, PUT, DELETE, etc.) will result in "hello, default".
The default method used by Spring request mapping is GET, so if you specify a request mapping with only #RequestMapping annotation, Spring will route all GET requests for the value of the annotation to this method.
To use any other method you basically need to say the method in the annotation. like #RequestMapping(method = RequestMethod.POST)
So for your example the first method will only handle the GET requests, while the other will handle the POST requests exclusively.
Usually GET in OAuth is used for normal interpretations, while the POST is used to authenticate un-authenticated users using the param passed to the method, which in this case is OAuth2Utils.USER_OAUTH_APPROVAL.
How are the two #RequestMapping annotations interpreted?
First of, from http://javatechig.com/java/spring/how-spring-controller-request-mapping-works-in-spring-mvc the default is interpreted as a GET. This is the first distinction. Second the paramaters of both methods are slightly different where method 1 requests a Map<String, String> and the other method Map<String, ?>. So even if both methods were GET, it would still make the distinction on parameter level.
Does the one that specifies POST exclusively handle all POST
/oauth/authorize requests, and does the one that does not specify a
method exclusively handle any non-POST requests to /oauth/authorize?
Or do both methods overlap, with both methods being called for certain
requests?
The POST exclusively handles post and nothing else. The other method only handles GET requests. They never overlap. As is java's law and Spring is still bound by the rules of the java overlords =)
I have a filter that implements a custom convention for loading servlets and JSPs. In that convention I am using the following code to include the servlet:
servletContext
.getRequestDispatcher( uriDispatcherLocator.getServletLocation( uri ) )
.include( request, response );
and the following code to include the JSP (in the same filter):
servletContext
.getRequestDispatcher( "/index.jsp" )
.include( request, response );
Everything works fine, the servlet executes, then it includes the JSP and some irrelevant custom rules take place.
As you can see, at the very moment I include a servlet with request dispatcher I cannot send an http header response to the client.
The problem is that I want the servlet to have full control of the response as if it was called from inside the filter (because the filter will do nothing else than dinamically mapping the servlets according to their respective Class/JSP location in the project file system).
I can use .forward() instead of .include(), but if I do I will not be able to include a JSP after the servlet has been executed.
So, how would I allow the servlet to execute the code below when being included through a filter via RequestDispatcher interface?
response.sendRedirect( "/somePath" );
No Javascript hacks, I am willing to send the proper HTTP response from the server to make the browser behave correctly.
--
EDIT:
In other words:
I want to change the headers sent to the client from INSIDE an included servlet by using RequestDispatcher, but the docs states:
The included servlet cannot change the response status code or set headers; any attempt to make a change is ignored.
Your Filter includes your servlet
servletContext
.getRequestDispatcher( uriDispatcherLocator.getServletLocation( uri ) )
.include( request, response );
Your Servlet indicates it wants to redirect
request.setAttribute ("sendRedirect", "/some/path");
or, wishes to add one or more response headers
Map<String, String> respHeaders = new HashMap<String, String>();
respHeaders.put("Expires", "0");
respHeaders.put("Cache-Control", "no-cache");
request.setAttribute("respHeaders", respHeaders);
Your Filter checks for these special requests
Map<String, String> respHeaders =
(Map<String, String>) request.getAttribute("respHeaders");
for (String key : respHeaders.keySet()) {
response.setHeader(key, respHeaders.get(key)); // set response headers
}
String sendRedirect;
if ((sendRedirect = (String) request.getAttribute("sendRedirect")) != null) {
response.sendRedirect(sendRedirect); // redirect the client
}
EDIT: Perhaps some of your servlets are already driving the flow and setting response headers when called from outside an include. But, there's no way to reuse them as is. You can't simply include them and expect the same behaviour because the goal of a RequestDispatcher#include() is to provide for server-side includes (SSI) only.
Hence, we do not find any overloaded methods (or any setters that could modify this behaviour) in the API. If you want to include such servlets and retain their behaviour (like redirects) you would have to pass them a hint that they're running under an include context and so should submit their response requests.
request.setAttribute ("includeContext", true);
In my web application , I get a request from the client. I process the request in my jsp page or the servlet(which ever is called) and want to forward to other jsp's or servlets accordingly. But before forwarding I want to set a few parameters and then forward it with these new parameters. The old parameters should not be present when forwarding. Only the new parameters should be present. How can this be done?
Can I forward from a servlet to jsp and vice-versa?
Please tell how the above can be accomplished?
If you have no use for the request parameters and your jsp/servlet has not written anything to the response, then I suppose it would be fine to use redirect instead of forward, since redirecting will discard the request along with the parameters.
When you do redirect, you can create dynamically and set the querystring like so:
response.sendRedirect("url?a=" + var1 +"&b=" + var2);
Take note that this will be a GET method to the url. If url will be resolved to a servlet, you can implement the doGet method to just call the doPost.
Please note that a redirect will be ignored if the jsp/servlet has written something already on the response...
You can use request dispatcher and redirect as per your need and requirement.
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher("url");
rd.forward(request,response);
or
response.sendRedirect("url");
sendRedirect() sends the header back to the browser , which contains the name of the resource to be redirected to. So this will be a new request to the resource from the browser .
forward() action takes place within the server without the knowledge of the browser .
yes you can forward the parameter servlet to jsp and jsp to servlet.
when you can set the attribute in request then it will lost on destination.means you can not access that on third resource.
request.setAttribute(attribute name,attribute value)
you can do same thing in session also.
You have to forward to JSP/Servlet using RequestDisptcher. Set the request attribute on the request to set parameters using
request.setAttribute(name, value)
The Forwarded JSP can read the parameter using
request.getAttribute(name)
But, You cannot hide the attribute existing before forward by default. You can achieve this using Request Wrapper. Wrap the request before forwarding override the set and get attribute methods.
Below code explains
RequestDisptcher dispatcher = req.getRequestDispatcher("url");
HideExistingRequestWrapper requestWrapper =
new HideExistingRequestWrapper(request);
requestWrapper.setAtribute("forwarded", "forwarded value");
dispatcher.forward(requestWrapper, response);
Here is the code of wrapper implementation:
class HideExistingRequestWrapper extends HttpServletRequestWrapper {
private Map localattributes = new HashMap();
public HideExistingRequestWrapper (HttpServletRequest orignialRequest) {
super(orignialRequest);
}
public Object getAttribute(java.lang.String name) {
return localattributes.get(name);
}
public Object setAttribute(java.lang.String name, java.lang.String value) {
return localattributes.put(name, value);
}
}
use
ServletRequest.removeAttribute(name of your old attribute)
ServletRequest.setAttribute(name , value)
After setting the attributes, get the RequestDispatcher using
getRequestDispatcher(url)
and then use forward() method
I am using the json spring view in order to return a simple JSON object from my controller.
The problem is that its returning more data then i want. it is returning the validation errors and things inside of my model when all i am doing is this in the controller:
Map model = new HashMap()
model.put("success", "true");
return new ModelAndView("jsonView", model);
If you look at the bottom of this page in the docs it looks like i am getting back data that POST would return. i am not doing a post, i am doing a GET by going directly to the URL with params.
How do i get this lib to return just the data in my model?
We have used this library and it has worked as expected. Could you try with the following variation of the above code to see if it works? We use this in some places...
ModelAndView modelAndView = new ModelAndView("jsonView");
ModelMap map = modelAndView.getModelMap();
map.addAttribute("success", "true");
return modelAndView;