requesting parameters from jsp - spring

I have some problems with taking a parameters from jsp page, when method POST occurs.
My JSP page looks like this:
....
<table border="1">
<tr>
<th>name</th>
<th>check</th>
</tr>
<c:forEach items="${things}" var="pair">
<tr>
<td>${things.name}</td>
<td><INPUT TYPE="CHECKBOX" NAME=items VALUE=${things.id} ></td>
</tr>
</c:forEach>
</table>
<form method="post">
<input type="submit" value="Check all" />
</form>
So, I want to take all checked "things" in table. In controller class I something like this (written in Spring):
....
#RequestMapping(method = RequestMethod.POST)
public String sumbitForm(#RequestParam("items") String[] items){
if(items!= null){
for(String item: items){
....
}
}
return "redirect:myPage";
}
But my app don't want to work with such RequesParam. It doesn't put the values of items parameter to it. (this method I took here http://www.go4expert.com/forums/showthread.php?t=4542)
Also I tried using #ModelAttribute instead of #RequesParam. When I'm using it, my app don't give a errors, but it also couldn't correctly put the "items" to this parameter.
Any ideas?
P.S. May be you know more better method of taking list of parameters from JSP page for using their values (like taking checked items)?

Your table is outside of the <form></form> so when submitting, it doesnt send anything.

Related

Thymeleaf th:field doesn't bind the value for input text

I want to send an object to the view for presentation and send it back to controller using springboot and Thymeleaf, however, I encounter a weird problem with Thymeleaf's th:value.
This is my controller:
#GetMapping("/food/buy/{fid}")
public String buyFood(HttpServletRequest request, #PathVariable("fid") Long fid, Model model) {
Food food = consumerService.getFood(fid);
System.out.println("foodid = " + food.getId());
model.addAttribute("food", food);
model.addAttribute("order", new OrderVO());
return "user/direct/f_order";
}
and my view:
<form th:action="#{/user/buy/direct/food}" method="post" th:object="${order}">
<table border="1px">
<tr th:hidden="true">
<td><input type="text" th:value="${food.id}" th:field="*{fid}" th:readonly="true"></td>
</tr>
</table>
</form>
and the VO class:
public class OrderVO {
private Long fid, address;
private Integer amount;
#DateTimeFormat(pattern = "HH:mm")
private Date deliverTime;
}
the problem is, the input field's value is null, but I'm sure that the food's id is not null (I print it in the controller)
I remove the th:field block, and the food.id can be properly presented. If I add the th:field block back, the problem reoccur.
So there may be something wrong with th:field, but I can't figure out. Can somebody point out my mistake?
===========================UPDATE============================
Some friends kindly points out that th:field may overwrite th:value, but I also use them in other views and it works fine:
<tr>
<td>UserName</td>
<td><input type="text" th:value="*{userName}" th:field="*{userName}"></td>
</tr>
The problem is getting incresing weird I think :(
Replace *{fid} with fid
My team had this same issue and it worked
In tabualr form try using th:name instead of th:field to overcome th binding issue
th:name="|order.fid|"
and stick to java naming convention.
Supposing you have to collect a comment to a page. You must transmit to the controller, besides the comment, the name of the page. Ofcourse, the user don't have to re-enter the name of this page. This information must be passed to controller, but th:field only map the values entered by the user, not the values generated by default.
But you can transmit the name of this page to controller as parameter in URL.
In html, you have something like that:
<form th:action="#{/saveComment(lastPage=${lastPage})}" th:object="${comments}" method="post" enctype="multipart/form-data">
<div class="row">
.................................................................................
<h2>Enter your comment</h2>
<textarea th:field="${comments.comment}" rows="10" cols="100" name="comment" id="comment"></textarea>
<label for="comment">Your comment here</label><br />
<input type="submit" name ="submit" value="Submit" />
</div>
</form>
In controller, you put stuff like this:
#PostMapping("/saveComment")
public String saveComment(Comments comments, String lastPage) {
comments.setPage_commented(lastPage);
commentsRepository.save(comments);
return "redirect:/";
}
It works fine to me.

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).

How to send back the model data from jsp to controller

I have a controller which sets few values to a model and sends to jsp. In jsp i need to show those values(as labels) along with additional values from user as input values. When i submit the jsp i only get valid values that user has entered and the values set earlier by controller is null.
JSP
<form:form
action="${pageContext.request.contextPath}/admin/deviceAction.html"
modelAttribute="deviceData">
<table class="gridtable" width="500px">
<tr>
<td>Device Name : </td>
<td>${deviceData.deviceName}</td>
</tr>
<tr>
<td>Model Name : </td>
<td>${deviceData.modelName}</td>
</tr>
<tr>
<td>Serial No : </td>
<td>${deviceData.serialNo}</td>
</tr>
<tr>
<td>Device Id : </td>
<td>${deviceData.deviceId}</td>
</tr>
<tr>
<td>Status : </td>
<td>${deviceData.statusCode}</td>
</tr>
<tr>
<td>Action : <span class="required">*</span></td>
<td>
<form:select path="deviceAction" >
<form:option value="" label="--- Select ---" />
<form:options items="${model.actionList}" />
</form:select>
</td>
</tr>
</table>
<input type="submit" value="Submit" id="btn_submit">
</form:form>
Controller:
public ModelAndView beforeSubmit() {
ModelAndView modelView = new ModelAndView();
DeviceData deviceData = new DeviceData();
deviceData.setDevicePk("123");
deviceData.setAccessToken("abcwetrwertewrtetr");
deviceData.setDeviceId("deferterterterterwtetetertg");
deviceData.setDeviceName("test");
deviceData.setEnrolledDate("7-8-13");
deviceData.setModelName("test1");
deviceData.setSerialNo("test2dsfgdfgdfg");
deviceData.setStatusCode("test3");
List<String> actionList = getActionList();
Map<String, List<String>> model = new HashMap<String, List<String>>();
model.put("actionList", actionList);
modelView.addObject("deviceData", deviceData);
modelView.addObject("model", model);
modelView.setViewName("admin/tokenSearchResult");
}
public ModelAndView afterSubmit() {
#ModelAttribute("deviceData") DeviceData deviceData, BindingResult result) {
logger.info("#################device datas are : " + deviceData.getDevicePk() + "###### " + deviceData.getDeviceAction());
return new ModelAndView();
}
deviceData.getDevicePk() is null
Only the drop down value is having valid value. Other values displayed in the screen are received as null.
Edit:
Till now i have found only one solution:
<form:input path="deviceName" readonly="true" />
But this way UI does not looks good. The editable and non editable values mixup in the screen. Looking for a better answer
Finally i am using hidden parameters to solve the problem.
Example:
<td>${deviceData.deviceName}</td>
is replaced by:
<td><form:hidden path="deviceName"</td>
By this way it helps me to avoid any css work(which i am not much comfortable)
If anyone get a better solution kindly post it here
You need to make them into form inputs using the Spring form tags in much the same way as you have for the form:select. If they are not editable by the user, you can always disable them.
You can simple hide those input. For example :
<input type="hidden" name="VehSeriesModelId" value="${vehDetailsVM.id }">
This way, you can get the data to the controller and the user will also not be able to edit the value. On the other hand, your form will also not show it :)

Passing object from JSP to spring controller

I have the below table in a .JSP page:
<form:form method="post" action="update.dtt" id="contactForms" modelAttribute="contactForms" >
<c:forEach items="${pList}" var="cf">
<tr>
<td align="center"><c:out value="${cf.fname}" /></td>
<td align="center"><c:out value="${cf.lname}" /></td>
<td align="center"><c:out value="${cf.cprovider}" /></td>
<td align="center"><c:out value="${cf.id}" /></td>
<td align="center"><c:out value="${cf.phone}" /></td>
<td><input type="submit" value="Update Contact"/></td>
</tr>
</c:forEach>
</form:form>
I'm iterating over the list (this is list of objects) and adding an Update Contact button for each record in the list. How can I pass on the particular instance (object) to the controller when the Update button is clicked?
The controller I have is as below. However I'm getting null.
#RequestMapping(value = "/user/update.dtt", method = RequestMethod.POST)
public String updateView(#ModelAttribute("contactForms") Banks bank, HttpServletRequest request, HttpServletResponse response, Model model) {
System.out.println("*First Name*" + bank.getFname());
//......
return "detailBank"; //name of jsp file
}
You'll need to have a hidden form field for each information you want to send to the server.
Since you have one button for each row, you should also have one form for each row. So the <form:form> and </form:form> lines should be inside the <c:forEach>, and not outside.
You need reference the instance by position, accessing to the element of the list by position.
list[i].name
list[i].surname
where list is the element in your pojo.

Spring MVC 3 Validation will not work when attributes added to model

I'm trying to get Spring annotation based validation working in a simple webapp. I'm using Spring 3.0.5, Tiles 2.2.2. In one specific case I can get the validation error to appear next to the field, however as soon as I add any objects to the model it stops working. Ideally, after the POST, I want to redirect to a GET of the form with the validation errors included. This is the setup:
I have a simple domain object.
public class DomainObject {
#NotEmpty
private String name;
private Date created;
private Date lastModified;
...
}
I have a controller with a GET method which adds all existing DomainObjects to the model and returns a view that displays them, and contains a very simple form for creating them. It also has a POST method for creating a new DomainObject.
#Controller
#RequestMapping("/")
public class DomainObjectController {
#Autowired
private DomainObjectService domainObjectService;
#RequestMapping("form.htm")
public String home(Model model) {
model.addAttribute("objects", domainObjectService.getAll());
model.addAttribute(new DomainObject());
return "form";
}
#RequestMapping(value="new_object.do", method=RequestMethod.POST)
public String newObject(#Valid DomainObject domainObject, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
//model.addAttribute("objects", domainObjectService.getAll());
//model.addAttribute(new DomainObject());
return "form";
}
domainObjectService.saveNew(domainObject);
model.addAttribute("objects", domainObjectService.getAll());
model.addAttribute(new DomainObject());
return "form";
}
}
Here's the view:
<form:form commandName="domainObject" action="new_object.do" method="post>
<spring:message code="name" />: <form:input path="name" />
<input type="submit" value="<spring:message code="create.object"/>" /><form:errors path="name" cssClass="error"/></form:form>
</div>
<table class="centered">
<col width=50 />
<col width=225 />
<col width=200 />
<col width=200 />
<thead>
<tr>
<td id="id" class="sortable"><spring:message code="id" /></td>
<td id="name" class="sortable"><spring:message code="name" /></td>
<td id="created" class="sortable"><spring:message code="created" /></td>
</tr>
</thead>
<tbody>
<c:forEach var="obj" items="${objects}">
<tr>
<td class="id">${obj.id}</td>
<td>${obj.name}</td>
<td>${obj.created}</td>
</tr>
</c:forEach>
</tbody>
</table>
With this setup, if I leave the name field empty, the validation error is picked up and correctly displayed to the right of the field. However, the table is always empty, as no objects are added to the model. If I add objects to the model, by uncommenting the lines
//model.addAttribute("objects", domainObjectService.getAll());
//model.addAttribute(new DomainObject());
the table is populated but the validation error no longer appears. I can't work this one out.
As another unwanted side effect, any relative links I have in the view now no longer work (for example, a link which changes the locale href="?lang=de").
So, what could be causing the validation message to disappear when I add data to the model? And is it possible for me to redirect to the original form while keeping hold of the validation messages?
Thanks,
Russell
The validation error is attached to the object that is invalid. If you replace the object that is invalide by an new one:
model.addAttribute(newDomainObject());
then the error messages is not attached to this object.

Resources