How to get and post parameter from url - spring

I got a page link like www.example.com/resetPassword?pass=33 and I can get this value from controller method with using #RequestParam method.
Problem is I also need this parameter(pass) value when I post this page(form).When I post below form url changes to www.example.com/resetPassword but I want also paramter as www.example.com/resetPassword?pass=33.Is there an easy way to achieve this?
Here is my form;
<form:form action="resetPassword.htm" role="form" method="POST">
....
</form:form>
My controller method;
#RequestMapping(value = "/resetPassword.htm*", method = {RequestMethod.GET, RequestMethod.POST})
public ModelAndView resetPassword(HttpServletRequest request, HttpServletResponse response, #RequestParam("pass") String pass){
if(request.getMethod().equals("GET")){
//
}
else if(request.getMethod().equals("POST")){
//
}
}

This is in general a bad idea. You are breaking restful convention.
The different request types normally have different behaviour, don;t try and combine them.

Related

FlashAttributes not in model after redirect

I have this controller method:
#GetMapping("/notations")
public String listAll(Model model) {
Iterable<PriceNotation> allItems = loadAllNotations();
model.addAttribute("notations", allItems);
return "supply/notations";
}
Then I have this method which redirects to the one above:
#GetMapping(value = "/notations/delete")
public String delete(#RequestParam(name="id", required=true) Long id, RedirectAttributes redirectAttributes)
{
try {
notationRepository.deleteById(id);
} catch (RuntimeException e) {
redirectAttributes.addFlashAttribute("message", "delete failed");
}
return "redirect:/notations";
}
When I put a breakpoint in the first method after a redirect, the model is empty. Although the documentation says:
After the redirect, flash attributes are automatically added to the
model of the controller that serves the target URL.
Also in my html page I have this header which should display the message:
<h2 th:text="${message}"></h2>
Also this header is empty. What am I missing?
PS, I know this question has been asked before but there was no accepted answer and none of the suggestions worked for me.
they are not added to model as they are passed as query parameters like example.com?message=abc.
So you can either:
access them in controller with #RequestParam and then add to your model
OR access them in thymeleaf with ${#param.message[0]}
in summary you should treat redirectAttributes as reqular query parameters in receiving controller (listAll).

Spring modelattribute not recognized anymore after ajax update

i´ve encountered the following issue several times:
I use a Controller to bind a dto to a html form (via thymeleaf). Please note the model named "invoiceDto"
#RequestMapping(value = {"/create"}, method = RequestMethod.GET)
public String create(Locale locale, Model model) throws Exception {
final String login = this.getAuthentication().getCurrentApplicationUser();
if (login == null || login.isEmpty())
throw new Exception(this.getMessageSource().getMessage("label.findError", null, locale));
final Future<Setting> setting = settingService.findFirst();
final Future<ApplicationUserContactProjection> applicationUserContactProjection = applicationUserService.findByLogin(login);
while (!setting.isDone() && !applicationUserContactProjection.isDone()) {
Thread.sleep(100);
}
if (setting.get() == null || applicationUserContactProjection.get() == null)
throw new Exception(this.getMessageSource().getMessage("label.error.findError",
null, locale));
model.addAttribute("invoiceDto", new InvoiceDto(setting.get(), applicationUserContactProjection.get()));
model.addAttribute("message", this.getMessageSource().getMessage("label.navigation.invoiceCreation", null, locale));
return "invoice/create";
}
I have a html form (thymeleaf generated) where i use the above Java pojo dto with the given modelattribute name to fill my Input fields. This is an excerpt of it. The important part is the div with the id of "invoiceLineItems" where thymeleaf replaces its child div with a lineItems Fragment:
<form action="#" th:action="#{/invoice/newinvoice}" th:object="${invoiceDto}" role="form" method="post"
class="form-signin" id="editInvoiceForm"
accept-charset="utf-8">
<div id="invoiceLineItems"><div th:replace="invoice/items :: lineItems"></div></form>
The fragement contains the following stuff - an excerpt of it:
<td>
<input type="text"
th:field="*{items[__${index.index}__].lineItemTotalPrice}"
readonly
class="form-control" disabled
id="lineItemTotalPrice"/>
</td>
Excerpt of the given pojo:
public class InvoiceDto implements Serializable {
private Invoice invoice;
private List<LineItem> items;
I access the list like this:
th:field="*{items[__${index.index}__].lineItemTotalPrice}"
The Problem:
I can add items dynamically via Ajax. I serialize the whole form (for convenience reasons) and call a Controller Method:
#RequestMapping(value = {"/newlineitem"}, method = RequestMethod.POST)
public String newLineItem(#ModelAttribute("invoiceDto") InvoiceDto invoiceDto,
Model model)
throws Exception {
invoiceDto.addItem(new LineItem());
final Future<InvoiceDto> calculatedInvoiceDto = invoiceService.calculateInvoice(invoiceDto);
while (!calculatedInvoiceDto.isDone()) {
Thread.sleep(100);
}
model.addAttribute("invoiceDto", calculatedInvoiceDto.get());
return "invoice/dynamicitems :: lineItems";
}
As you can see, i let thymeleaf render a Special view, because after the Ajax success spring cannot set the modelattributes proper.
In short: After the Ajax Returns the partial view, the following will throw an exception:
th:field="*{items[__${index.index}__].lineItemTotalPrice}"
whereas this works - note the prefixed invoiceDto:
th:field="*{invoiceDto.items[__${index.index}__].lineItemTotalPrice}"
Question:
What´s wrong here?
Why do i have to prefix the name of the modelattribute after the partial Ajax update, whereas in the first run i don´t have to?
Thank you for your help!
EDIT:
For my share it looks like the way that spring "forgets" the originally named form modelattribute "invoiceDto" if the page is partially updated by an ajax call (to another spring controller, modifying invoiceDto) through a partial thymeleaf html.
So after the controller returns the partial thymeleaf view i have to access its fields with prefixed "invoiceDto", as if there would be no invoiceDto attribute.
Thanks again for your help!
UPDATE
As there is no progress on this i have raised a thymeleaf issue:
https://github.com/thymeleaf/thymeleaf/issues/795
Nevertheless i think this is a spring issue, because i have the same results with JSP.
Repository to comprehend this issue
https://mygit.th-deg.de/tlang/thymefail
If I understand your problem correctly, you're trying to use the *{} notation when there is no active object. When the ajax method returns just the "lineItems" fragment, Thymeleaf has no way of knowing that it belongs to a form with a th:object on it.
I guess the best solution is to return the whole form then, in js, extract the lineItems.
Or maybe just get rid of th:object altogether (convenient only when you want to show validation errors imho).

Why I can't redirect from a Spring MVC controller method to another controller method?

I am pretty new in Spring MVC and I have some problem trying to redirect to a controller method after that another controller method terminate its execution.
So I have the following situation. Into a controller class I have this method that correctly handle POST request toward the validaProgetti resource:
#RequestMapping(value = "validaProgetti", method=RequestMethod.POST)
public #ResponseBody String validaProgetti(#RequestBody List<Integer> checkedRowList) {
System.out.println("ID progetti da aggiornare: " + checkedRowList);
List<Twp1007Progetto> progettiDaValidare = new ArrayList<Twp1007Progetto>();
for (int i=0; i<checkedRowList.size(); i++) {
System.out.println("ID PROGETTO: " + checkedRowList.get(i));
progettiDaValidare.add(progettoService.getProgetto(checkedRowList.get(i)));
}
progettoService.validaProgetti(progettiDaValidare);
return "redirect:ricercaValidazione";
}
So this method is correctly mapped and when the validaProgetti resource is called it is executed.
At the end of this method I don't return a view name that render a JSP page but I have to redirect to another method (that do something and render a JSP page). So, instead to return a view name, I redirect toward another resource:
return "redirect:ricercaValidazione";
Then in the same controller class I have declared this method that handle request toward this ricercaValidazione resource:
#RequestMapping(value = "ricercaValidazione", method=RequestMethod.POST)
public String ricercaValidazione(#ModelAttribute ConsultazioneFilter consultazioneFilter, Model model, HttpServletRequest request) {
RicercaConsultazioneViewObject filtro = null;
try {
filtro = new ObjectMapper().readValue(request.getParameter("filtro"), RicercaConsultazioneViewObject.class);
filtro.setSelStatoProgetto(3); // Progetti da validare
} catch (IOException e) {
logger.error(e);
}
consultazioneFilter = new ConsultazioneFilter(filtro);
model.addAttribute("consultazioneFilter", consultazioneFilter);
model.addAttribute("listaProgetti", new ListViewObject<Twp1007Progetto>(progettoService.getListaProgettiConsultazione(consultazioneFilter)) );
return "validazione/tabellaRisultati";
}
The problem is that it can't work and after the redirection can't enter into the ricercaValidazione() method.
I think that maybe the problem is that this ricercaValidazione() method handle POST request toward the ricercaValidazione resource and the return "redirect:ricercaValidazione"; maybe generate a GET request.
But I am not sure about it.
Why? What am I missing? How can I solve this issue?
Tnx
the redirect and fordward prefix are for resolving views; you are tring to redirect from one controller to another one. This can be done but redirect works in the following way
A response is sent to the browser with the redirect http status code and and url
The browser loads via GET the request URL
Your Spring controller (and the corresponding ammping method) is invocated if it matches the annotation params
From what you write I'm not sure this is what you really want; as you already noted there is a mismatch between HTTP methods (GET vs POST).
Your second method ricercaValidazione expects a filtro param in order to filter some data, but in the validaProgetti there is nothing similar, so it seems that the two controllers are not directly chainable. If what you want is to display a page after validaProgetti that shows a form and the the user can submit it you must add a method annotated with a method GET and url ricercaValidazione; the new method must return the view containing the form; which points via POST to url of validaProgetti. In this way you can redirect from ricercaValidazione to validaProgetti
Give mapping name of your controller with redirect like
redirect:/controll-mapping_name/ricercaValidazione
have a look on this question
Unable to redirect from one controller to another controller-Spring MVC

Can a Spring MVC controller return both a HttpServletResponse and a view?

My existing code is like:
String myController(#PathVariable someId, ModelMap map){
....
return "myViewName";
}
Now I want to set a cookie in some cases, so I need to get hold of a HttpServletResponse obj. Can I just add such a response obj to the list of params and operate on it in the controller?
If so, I wonder how my own response is kind of reconciled with the response generated by the JSP that resolves the "myViewName".
Yes.
#RequestMapping
public String myController(#PathVariable someId, ModelMap map, HttpServletResponse response) {
// Do what you need to do on the response, like set a cookie
return "myViewName";
}
Regarding your other question : "how my own response is kind of reconciled with the response generated by the JSP that resolves the "myViewName"."
When you return a view say "myViewName", it will be resolved to a particular resource (JSP View or JSON View or any other view). Once that view resource is obtained depending on what you return, that view does the rendering on to the response. This response object is the same that was passed to the controller function (myController). So say if you set some cookie/headers on the response in the controller function, the response that is being used by the view to do the rendering will also have the same properties.
In case you want to handle the actual rendering/response yourself, you can always get the outputstream of the response and write to it and close the stream. Then the view that you return is just ignored as the dispatcher will check that the response is already handled and will just do post handle stuff.
Hope that clears up for anyone looking for the dispatcher logic behind it.

How to deal with error "Request method 'GET' not supported"

I would like to implement deletion of a entity from a list view. And I faced this problem. Can you explain me, what is the problem and how can I ovrcome it?
The controller method:
#RequestMapping(value = "/deleteComment/{commentId}", method = RequestMethod.POST)
public String deleteComment(#PathVariable int commentId, BindingResult result, Model model){
{
Comment deletedComment = commentService.findCommentByID(commentId);
if (deletedComment != null) {
commentService.deleteComment(deletedComment);
}
return "refresh:";
}
Do I need to specify 'Get' method, if I'm dealing with list-view (and I see the whole list). If I need, what code should I place there. I have no any ideas...
The problem is in button type attribute.
If You have HTML button type="submit" then Your service can be only RequestMethod.GET. When You change to RequestMethod.POST then You have "Request method 'GET' not supported".
SOLUTION: Change attribute in button tag to type="button".
By specifying method = RequestMethod.POST you are essentially saying that the deleteComment method should be called only for POST and for a path /deleteComment/{commentId}. If you want it to accept requests for GET also, you can just remove the method or accept GET also this way:
#RequestMapping(value = "/deleteComment/{commentId}", method = {RequestMethod.POST, RequestMethod.GET})
You may also want to explicitly specify the name of the variable to bind to the commentId path variable this way:
public String deleteComment(#PathVariable("commentId") int commentId, BindingResult result, Model model){

Resources