Redirect on controller advice expectionhandler with model attribute spring MVC - spring

So i try to redirect from ExceptionHandler wit model attribute to the site where it was caused.
For example i have a controller method witch list the current items:
#AvailableInMenu
#RequestMapping(method = RequestMethod.GET)
public String list(Model model) {
model.addAttribute("Companys", iCompanyService.findAll().getData());
return "masters/crud/company/list";
}
An this is the template witch the method call:
<div th:if="${exception != null}" class="alert alert-warning alert-dismissible" role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
<strong>Warning!</strong><div th:text="${exception}" th:remove="tag" ></div>
</div>
<div class="ibox float-e-margins">
<div class="ibox-content">
<table id="table" class="table table-striped table-bordered nowrap">
<thead>
<tr>
<th th:text="#{app.maintanance.installversion}"></th>
</tr>
</thead>
<tbody>
<tr th:each="company : ${Companys}">
<td th:text="${company.installversion}"></td>
<td>
<a class="delete-button" th:attr="data-redir=#{/company/delete/{id}(id = ${company.id})}">
<i class="fa fa-pencil"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
This thymeleaf code generate a table with data and a delete link. Th entity wotch the user use has foreign key, and if the user want to delete it jpa thows a foreign key constraint witch i wrap into an error wrapper.
This is the controller method for the delete link:
#RequestMapping(value = {"/delete/{id}"}, method = RequestMethod.GET)
public String deleteCompany(Model model, #PathVariable("id") Long id) {
ErrorWrapper<Boolean> result = iCompanyService.deleteCompany(id);
if(result.hasError()){
if(result.getConstraint()){
throw new GlobalModelException(601L, "redirect:/company");
}
}
return "redirect:/company";
}
AS you can see if there was an error i throw general exception that i create, and a ControllerAdvice with ExpectonHandler where is catch my expection class. I want to add the exception to model and redirect back to the listing site, and show the bootstrap alert to the on the site.
This is the exceptionHandler from the ControllerAdvice
#ExceptionHandler(GlobalModelException.class)
public ModelAndView handlingException(GlobalModelException exception) {
ModelAndView model = new ModelAndView();
model.setViewName(exception.getUrl());
model.addObject("exception", exception);
return model;
}
The ModelAndView redirect me the correct place as it should be, but the exception is null after redirect. How can i call my listing site with the exception in the model with ControllerADvice. I have many other exceptions that i want to handle and a a lot of other controller where i need this.
Is there any way to do this?

You mush use RedirectAttributes/FlashAttribute.
http://viralpatel.net/blogs/spring-mvc-flash-attribute-example/
http://www.baeldung.com/spring-redirect-and-forward

Related

When to use #RequestMapping, #GetMapping and #PostMapping in Spring Boot?

On my home page I want to populate the tables with data from the database.
Page home.html:
<div class="table-responsive">
<table class="table table-dark" id="userTable">
<thead>
<tr>
<th style="width: 20%" scope="col"></th>
<th style="width: 20%" scope="col">Title</th>
<th style="width: 60%" scope="col">Description</th>
</tr>
</thead>
<tbody>
<tr th:each="nota:${notas}">
<td>
<button type="button" class="btn btn-success"
th:onclick="javascript:showNoteModal(${nota.getId()},${nota.getTitle()},${nota.getDescription()})">Edit</button>
<a class="btn btn-danger"
th:href="${/eliminarNota(notaId=${nota.getId()})}">Delete</a>
</td>
<th scope="row" th:text="${nota.getTitle()}">Example Note Title</th>
<td th:text="${nota.getDescription()}">Example Note Description </td>
</tr>
</tbody>
</table>
</div>
What annotation should I use in the method the class Controller:
#Controller
public class InicioController {
private NotaService notaService;
public InicioController(NotaService notaS){
this.notaService = notaS;
}
#RequestMapping("/inicio")
public String obtenerDatosUsuario(Model model,FormNota formNota){
return "home";
}
}
When working with server rendering frameworks like thymeleaf, its controllers can be divided into two groups for a better understanding:
Controllers to show the page content to your client
Controller to receive actions from your client
Show page content
Here #RequestMapping and #GetMapping are usually used. The main goal of this controllers is "merge" the html template with data from anywhere like a database:
#Controller
#RequestMapping({"/home" })
public class ViewController {
#Autowired
private StudentService service;
#GetMapping
public String viewHomePage(Model model) {
List<Student> studentList = service.listAll();
model.addAttribute("studentList", liststudent);
model.addAttribute("someField", "foo");
return "home";
}
}
Receive page actions
In this case #PostMapping is usually used.
#Controller
public class FormController {
#PostMapping("/save")
public String submissionResult(#ModelAttribute("personForm") Person person) {
return "result";
}
}
Samples
https://riptutorial.com/thymeleaf/example/29269/form-submission
https://github.com/dariawantech/spring-boot-thymeleaf-example

ModelAttribute not working with lists in spring

I want to bind a List using ModelAttribute. The list contains objects of type Transaction each of which contains transactionid (type int). This is my controller code:
#RequestMapping(value = "/approvecreditdebit.do", method = RequestMethod.POST)
public ModelAndView doActions(HttpServletRequest request,
#ModelAttribute("clc") Clc transactionList, BindingResult result,
ModelMap model) {
/*
* switch (action) { case "approve":
*/
System.out.println("Obj = " + transactionList.getClass());
System.out.println("Val = " + transactionList.getTransactionList());
Users users = new Users();
return new ModelAndView("internal","internal",users);
}
This is my jsp code:
<form:form action="approvecreditdebit.do" method="POST"
modelAttribute="clc">
<table border="1">
<tr>
<th>no</th>
<th>ID</th>
</tr>
<c:forEach items="${clc.transactionList}"
var="transaction" varStatus="status">
<tr>
<td>${status.index}</td>
<td><input name = "transaction[${status.index}].transactionId"
value="${transaction.transactionId}" /></td>
</tr>
</c:forEach>
</table>
<br>
<br>
<center>
<input type="submit" value="approve" />
</center>
</form:form>
This is the Clc class:
public class Clc{
private List<Transaction> transactionList;
public List<Transaction> getTransactionList() {
return transactionList;
}
public void setTransactionList(List<Transaction> transactionList) {
this.transactionList = transactionList;
}
}
The value of transactionList is not being set to the values received from the form. I receive the following error:
Request processing failed; nested exception is java.lang.NullPointerException
I tried searching for the solution on google and got a lot of solutions from stackoverflow but none of them seem to work.
Try something like this (notice the use of <form:input>). I just tried it on a simple Spring MVC app and it works (list is not null and has the values from the form when I try to access it in my POST method).
<c:forEach var="transaction" varStatus="status" items="${clc.transactionList}">
<tr>
<td>${status.index}</td>
<td><form:input path="transactionList[${status.index}].id" /></td>
</tr>
</c:forEach>

ModelAttribute returns null values in controller in Spring MVC

Ok, its time to seek help; I am sending a (shopping) Cart ModelAttribute to my jsp, allowing the user to edit the quantity, when the Model is POST to the controller the fields are null except the editable (quantity) field. I have researched for days on similar issues but nothing is matching. I am using spring 3.1.
Here is my controller on the GET and POST:
#Controller
public class CartController {
#Autowired
private Cart cart;
#RequestMapping(value = "/cart", method = RequestMethod.GET)
public String showCart(Model model) {
logger.debug("CartController.showCart() Cart: {}", this.cart);
model.addAttribute(cart);
return "cart/cart";
}
and POST
#RequestMapping(value = "/cart", method = RequestMethod.POST, params = "update")
public String update(#ModelAttribute("cart") Cart cart, BindingResult result, Model model) {
logger.debug("CartController.update() Cart: {}", cart);
return "cart/cart";
}
my jsp:
<div class="container MainContent">
<form:form method="POST" modelAttribute="cart">
<fieldset>
<legend>Cart</legend>
<table class="table">
<thead>
<tr>
<th>Product Name</th>
<th>Quantity</th>
<th>Product Price</th>
</tr>
</thead>
<tbody>
<c:forEach items="${cart.cartDetails}" var="cartDetail" varStatus="status">
<tr>
<td>${cartDetail.product.name}</td>
<td><form:input path="cartDetails[${status.index}].quantity" size="1" /></td>
<td>${cartDetail.price}</td>
</c:forEach>
<tr>
<b><td colspan="2" align="right"><spring:message code="order.total" /></b>
</td>
<td>${cart.totalCartPrice}</td>
</tr>
</tbody>
</table>
</fieldset>
<div></div>
<button id="order" name="order">
<spring:message code="button.order" />
</button>
<button id="update" name="update">
<spring:message code="button.update" />
</button>
</form:form>
</div>
and the log results for cart before on GET:
CartController.showCart() Cart: Cart [cartDetails=[CartDetail
product=com.Product#c26440[name=My Name],
quantity=1]], totalCartPrice=10.00]
and after updating the quantity from 1 to 3 in the jsp and then POST to the controller:
CartController.update() Cart: Cart [cartDetails=[CartDetail
[product=null, quantity=3]], totalCartPrice=null]
I've read several similar post here and on the Spring forum and tried different suggested solutions with no luck. It seems like my edited quantity results are getting bound to the Object correctly but why aren’t the others?
Assuming you have all the necessary fields in your Form object;
You have to specify the form fields and fill the value with your data.
<td>${cartDetail.product.name}</td>
will only print the result to the screen. If you want to bind it to your form you have to put it in a spring form input such as:
<form:input path="productName" value="${cartDetail.product.name}"/>
If you don't want it to be editable then you can put it into a hidden field but in the end you'll have to put it in a form element in the jsp and have a corresponding field in your form POJO
Seems other fields aren't bound, try to bind for example product name
<td>${cartDetail.product.name}
<form:hidden path="cartDetails[${status.index}].product.name" value="${cartDetail.product.name}"/></td>
I once spent a lot of time investigating a similar issue. Finally I found the culprit inside a Binder's initialization method:
#InitBinder
void initBinder(final WebDataBinder binder) {
binder.setAllowedFields("name", ...);
}
This method sets a restriction on fields that are allowed for binding. And all the other fields are unbound, naturally resulting in null values.
The other possible reason: incorrect setters in a Bean annotated with #ModelAttribute. For example, Object setName(String name) instead of void setName(String).

spring mvc mapping - send value between controllers

I have got webapp in spring 3 mvc. The case is that I have index page with url, when user click on them should be display another page with details of choosed information. Now the details page is shown but without any information (on index page is creating model with correct variable but not in details controller - in debug mode).
index controller method:
#RequestMapping(value="/{site}", method = RequestMethod.GET)
public String showDetails(#RequestParam(value = "site", required = true) String site, Model model){
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
return "details";
}
index html:
<form action="#" th:object="${product}" method="post" th:action="#{/details}">
<table border="0" width="600" th:each="sb, poz : ${product}" >
<tr >
<td rowspan="3" width="20"><span th:text="${poz.count}"></span></td>
<td>
<a th:href="#{/details/(site=${sb.tytul})}" th:value="${site}"><span th:text="${sb.tytul}"></span></a>
</td>
</tr>
<tr >
<td><span th:text="${sb.adres}"></span></td>
</tr>
<tr>
<td>category:<b><span th:text="${sb.category.name}"></span></b></td>
</tr>
</table>
</form>
details controller method:
#RequestMapping(value = "details/{site}", method = RequestMethod.GET)
public String showHomePage(#PathVariable(value = "site") String site, Model model){
model.addAttribute("product");
return "details";
}
details html:
<form th:object="${product}" method="get" th:action="#{/details}">
<table border="1" width="600" >
<tr >
<td ><span th:text="${tytul}"></span></td>
<td>
<span th:text="${opis}"></span>
</td>
<td><span th:text="${adres}"></span></td>
</tr>
</table>
</form>
I don't have any ideas how to map the details site (I tried a lot of solution but nothing). Thanks for help.
With thymeleaf, using th:object, you need to reference the fields of that object with *{}
<form th:object="${product}" method="get" th:action="#{/details}">
<table border="1" width="600" >
<tr >
<td ><span th:text="*{tytul}"></span></td>
<td>
<span th:text="*{opis}"></span>
</td>
<td><span th:text="*{adres}"></span></td>
</tr>
</table>
</form>
assuming tytul, opis, and adres are fields of product. Unless it's a type, don't forget
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
in your details controller method, otherwise you won't have a Catalog model attribute.
inside your details controller where are you setting product object in your model ?
model.addAttribute("product");
is just settingstring object "product", fetch the product object and set it in details controller like you have done in showDetails method
Change
model.addAttribute("product");
To
Catalog product = catalogEndpoint.getByTitle(site);
model.addAttribute("product", product);
in "showPage" method.

How to parse spring post data in rest?

I am developing an application in which i am using spring framework 3.1.1 and rest api. In it i have developed one rest controller which will on receiving "GET" request of url "/rest/host/{id}" will redirect the control to my view(form). Now after user fills up the form the posted data is also handled using rest. But in the method which i have written to handle post request all the parameters i am getting in one string which i want to parse and insert into the database. Can anybody tell which is the proper way to parse this spring data ? I can do it using String.split("&") but i don't think it is correct way to do that. Here is my code.
<form:form method="POST" action="/nagios-sms-1.0/rest/snooze/host/" commandName="snoozeBean">
<table width="100%" border="5" cellpadding="0" cellspacing="0">
<tr>
<td align="center">
<table width="50%" border="5">
<tr>
<td colspan="3"></td>
</tr>
<tr>
<td width="30%"><form:label path="contactNumber">Enter host address</form:label></td>
<td width="30%"><form:input path="contactNumber" /></td>
<td />
</tr>
<tr>
<td width="30%"><form:label path="snoozeTimeoutValue">Enter Snooze time</form:label></td>
<td width="30%"><form:input path="snoozeTimeoutValue" /></td>
<td />
</tr>
<tr>
<td colspan="3">
<div id="buttons"
style="margin-left: 20Px; margin-right: 100px;">
<input type="submit" value="ok" /> <input type="reset" />
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
REST code..
1) GET handler method
#RequestMapping(value = "/host/{hostId}", method = RequestMethod.GET)
public String snoozeHost(#PathVariable int hostId, ModelMap map) {
Snooze snooze = new Snooze();
snooze.setHost_id(hostId);
map.put("snoozeBean", snooze);
return "host";
}
2) POST handler method
#RequestMapping(value = "/host", method = RequestMethod.POST)
#ResponseBody
public String snoozeHostOK(#RequestBody String payload) {
// i want to parse this payload data which contains my form fields.
System.out.println("data : " + payload);
return payload;
}
Any kind of help will be appreciated. Thanks in advance.
Instead of request body you can use #ModelAttribute and get all the form data bind in one pojo(snooze) filled by Spring Framework on post of the form.
You need to declare snooze in your get and post request mapped method as #ModelAttribute. That will let you get all your values from the form.
UPDATE
See your modified code here.
GET handler method
#RequestMapping(value = "/host/{hostId}", method = RequestMethod.GET)
public String snoozeHost(#PathVariable int hostId, #ModelAttribute Snooze snooze, ModelMap map) {
snooze.setHost_id(hostId);
return "host";
}
POST handler method
#RequestMapping(value = "/host", method = RequestMethod.POST)
#ResponseBody
public String snoozeHostOK(#ModelAttribute Snooze snooze) {
// you can use the setter methods of snooze object to retrieve the field values.
return payload;
}
Hope this helps you. Cheers.

Resources