Getting null Set value in Post request from spring form - java

i am trying to get question and it's multiple options. i am getting successfully Question but its options getting null.
<c:forEach begin="0" end="${optionsCount}" varStatus="loop">
<form:input path="options[${loop.index}].mcq"/>
</c:forEach>
public class OnlineTestQuestionBean {
private String optionsCount;
private Long questionId;
private String question;
private Set<QuestionOptionBean> options;
//setter getter
}
public class QuestionOptionBean {
private Long optionId;
private String mcq;
//setter getter
}
following is Controller Code :-
#Controller
public class OnlineTestController {
#RequestMapping(value = "/savequestion", method = RequestMethod.GET)
public String addQuestion(Model model) {
model.addAttribute("OnlineTestQuestionBean", onlineTestQuestionBean);
return "addquestion";
}
#RequestMapping(value = "/savequestion", method = RequestMethod.POST)
public String saveQuestion(#ModelAttribute("OnlineTestQuestionBean")OnlineTestQuestionBean onlineTestQuestionBean, Model model) {
return null;
}
}
Following is Spring Form code :-
<c:forEach begin="0" end="${optionsCount}" varStatus="loop">
<form:input path="options[${loop.index}].mcq"/>
</c:forEach>
When i submit that time i get "Cannot get element with index 0 from Set of size 0, accessed using property path" this Exception,
suppose i used following code i get null set value.
<input type="text" path="options.mcq"/>

Try using the following in the form :
<c:forEach
<c:forEach items="${options}" var="option">
<form:input path="option.mcq"/>
</c:forEach>

Related

Thymeleaf post object to controller

I am new to Thymeleaf, I tried to post object to controller but didn't get any success. Here is a form template I am using:
<form id="customerRecord" th:action="#{/saveData}" method="post" th:object="${customerData}">
<input type="hidden" th:value="${name}" th:field="*{name}">
<button type="submit" class="btn btn-primary" >Save Record</button>
</form>
Controller:
#PostMapping("/saveData")
public String saveCustomerData(#ModelAttribute("customerData") CustomerData customerData, Model model) {
try {
LOG.info("Working {}", writer.writeValueAsString(customerData));
} catch (JsonProcessingException e) {
LOG.info("Problem");
}
return "success";
}
CustomerData class:
public class CustomerData {
private AuthorizeRequestItem name;
private AuthorizeRequestItem mobileNumber;
private AuthorizeRequestItem countryCode;
private AuthorizeRequestItem emailUser;
private AuthorizeRequestItem emailDomain;
}
AuthorizeRequestItem class:
public class AuthorizeRequestItem {
private Date date;
private String validator;
private Boolean valid;
private String data;
}
Problem is the CustomerData it self contain nested objects.
I need to pass complete CustomerData to controller, but when I tried to pass object in input field, it (controller) received a null value for nested objects of CustomerData.
I have implemented Thymeleaf forms to pass Objects containing string variable and it is working good for me.
Any help would be much appreciated.
This will work,when we are using post in thyme leaf we will use ajax call this will get your value and pass it to your controller now when you click submit button value will be pass to your controller.
For example:
<div id="form Data">
<input id="app Id" type="hidden" t h:value="${app Id}" />
<input type="submit" on click="redirection()"/>
</div>
<script type='text/java script'>
function redirection(){
let app id = document.get Element By Id('app Id').value;
let u r l ="this will be your u r l where you want to redirect"
window.open(u r l,"_self");

#ModelAttribute is returning null values with thymeleaf

After days of research I have trouble finding a solution for my controller methods. I have two controller methods that seem to be problematic. The savings method is saving null values. I have no clue how to bind the values, that are being typed into the field, to the list /all. One for creating values with input fields and another to save the input values and update a list /all. I want to get the values that I put into the fields of the form and have a updated list /all, with the new values. Note that I am only trying to save two of eleven attributes of the entire class. The class has double values and true/false. Those are being saved into db, except for the important String values. Thanks ahead for the help!
First method:
#GetMapping("/create")
public String showCreateForm(Model model, Branch branch) {
List<Branch> branches = new ArrayList<>();
BranchCreationDto branchesForm = new BranchCreationDto(branches);
for (int i = 1; i <= 1; i++) {
// the input field
branchesForm.addBranch(new Branch());
}
model.addAttribute("form", branchesForm);
return "branches/create";
}
This method is has one input field, where values of Branch can be set.
Second method:
#PostMapping("/saving")
public String saveBranches(#ModelAttribute BranchCreationDto form, Model model, Branch branch) {
// saves null but needs to be saving the values that are being typed into the field
this.branchRepository.saveAll(form.getBranches());
model.addAttribute("branches", branchRepository.findAll());
return "redirect:/all";
}
This method appears to have the problem at
this.branchRepository.saveAll(form.getBranches());
It is returning null values. I have already tried putting branch.getName(), branch.getType() into the parameter. This does not work.
With the method /all the programm is returning the list.
#GetMapping("/all")
public String showAll(Model model) {
model.addAttribute("branches", branchRepository.findAll());
return "branches/all";
}
This is my wrapper class
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
public class BranchCreationDto {
#Autowired
private List<Branch> branches;
public BranchCreationDto(List<Branch> branches) {
this.branches = branches;
}
public BranchCreationDto() {
}
public void addBranch(Branch branch) {
this.branches.add(branch);
}
public List<Branch> getBranches() {
return branches;
}
public void setBranches(List<Branch> branches) {
this.branches = branches;
}
}
And this is the form
<body>
<!-- Save -->
<form action="#" th:action="#{saving}" th:object="${form}"
method="post">
<fieldset>
<input type="submit" id="submitButton" th:value="Save"> <input
type="reset" id="resetButton" name="reset" th:value="Reset" />
<table>
<thead>
<tr>
<th>Branch</th>
<th>Type</th>
</tr>
</thead>
<tbody>
<tr th:each="branch, itemStat : *{branches}">
<td><input th:field="*{branches[__${itemStat.index}__].branch}" /></td>
<td><input th:field="*{branches[__${itemStat.index}__].type}" /></td>
</tr>
</tbody>
</table>
</fieldset>
</form>
You are doing wrong ,value do not pass from controller to thyme leaf by this way.I ll give you one example.
Example:
Controller:
Model and View model =new Model and View();
model .put ("branches", branch Repository.find All());
return model;
Thyme leaf:
<input id="branches" type="hidden" t h:value="${branches}" />
Now on your value is pass to id branches.
Just add the field as a hidden input and the thymeleaf will send your changes:
<input type="hidden" th:field="*{branches}"/>

Spring MVC: #PathVariable form

I have a data base which contains some items. I want to create a form which edits item with some id. I did it, form opens fine. Adress is /itemproject/edit_item/{id} Problems start when I'm trying to activate POST method. Instead of directing me to page with item list (/itemproject/view_items) programm sends me to /itemproject/edit_item/edit_item. itemproject is context path (for example).
#RequestMapping(value = "/edit_item/{id}", method = RequestMethod.GET)
public String editItem(#PathVariable("id") Integer id, Model model) {
Item item;
item = dbService.findItem(item).get(0);
model.addAttribute("item", item);
return "edit_item";
}
#RequestMapping(value = "/edit_item/{id}", method = RequestMethod.POST)
public String editItemComplete(#PathVariable("id") Integer id, #ModelAttribute("item") Item item, Model model) {
dbService.updateItem(item);
model.addAttribute("items",dbService.findAllItems());
return "view_items";
}
dbService works with data base.
I want that programm sent me to list of all items after ediding chosen item and updating it in database.
Here is example of edit form (url: /itemproject/edit_item/{id}
<spring:url value="edit_item" var="formURL"/>
<form:form action="${formURL}"
method="post" cssClass="col-md-8 col-md-offset-2"
modelAttribute="item"
>
<div class="form-group">
<label for="item-stuff">Stuff</label>
<form:input id="item-stuff"
cssClass="form-control"
path="stuff"/>
</div>
<button type="submit" class="btn btn-default">Edit item</button>
</form:form>
This is how my item list page looks (url: /itemproject/view_items)
<body>
<table class="table table-hover">
<tbody>
<tr>
<th>Stuff</th>
</tr>
<c:forEach items="${items}" var="item">
<tr>
<td>${item.stuff}</td>
</tr>
</c:forEach>
</tbody>
</table>
</body>
From Spring docs:
In Spring MVC you can use the #PathVariable annotation on a method
argument to bind it to the value of a URI template variable
That means that #PathVariable annotation is suitable when you use the GET method because when you use GET method you can pass your query string.
Instead, try to use #RequestBody in order to try to bind your POST HTTP body message to your parameter
For example:
#RequestMapping(value = "/edit_item", method = RequestMethod.POST)
public String editItemComplete(#RequestBody String body) {
//in here you'll have to pull the body content
return "view_items";
}
Let's say that you're sending an Integer id on HTTP POST body, then you can pull the data from the body like this:
#RequestMapping(value = "/edit_item", method = RequestMethod.POST)
public String editItemComplete(#RequestBody String body) {
ObjectMapper objectMapper = new ObjectMapper();
try {
idJson = objectMapper.readTree(body).path("id").asInt();
} catch (IOException e) {
e.printStackTrace();
}
return "view_items";
}
assuming that you're sending json from client to service.
Rather than loading the items and returning the view_items template, you can return "redirect:/itemproject/view_items" and that will cause your handler for view_items to be invoked, which will load the items etc.

How to bind a list of objects from a form in the View to the Controller in Spring 3

I hope i can explain my self clearly since I'm just starting with Spring.
Say I have the following bean:
public class UserAnswer {
private String answer;
public UserAnswer() {
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
This is a controller method that redirects to my view. Please note the parameters passed to the model
#RequestMapping(value="/usuarios/cambiar_estado", method=RequestMethod.POST)
public String bloquearDesbloquearUsuario(#RequestParam (value="usuarioPinIdHidden", required=false) String pinId, Model model){
try{
List<Question> questionList = servicioAcceso.getSecurityQuestionsByUser(Long.parseLong(pinId));
model.addAttribute("userAnswer", new UserAnswer());
model.addAttribute("questionList", questionList);
}catch(Exception e){
e.printStackTrace();
}
return "login/pregunta_seguridad";
}
This is the view login/pregunta_seguridad.jsp that renders a list of Questions. I need every element of the list
to be binded to a list of items of type UserAnswer:
<c:url var="url" value="/usuarios/compare_answers"/>
<form:form modelAttribute="userAnswer" action="${url}" method="POST">
<c:if test="${not empty answerList}">
<table class="summary" style="border: none;">
<c:forEach var="question" items="${questionList}">
<tr>
<td colspan="2">${question.description}</td>
</tr>
<tr>
<form:input path="answer" id="answer"/>
</tr>
</c:forEach>
</table>
</c:if>
<div class="span-3 last">
<button type="submit">Confirm</button>
</div>
</form:form>
I need a way to get a list of UserAnswer
#RequestMapping(value="/usuarios/compare_answers", method=RequestMethod.POST)
public String compareAnswer(Model model, UserAnswer userAnswer){
try{
//this is where I should receive a list of UserAnswer
}catch(Exception e){
e.printStackTrace();
}
return null;
}
How could I do something like that in Spring?
Thanks in advance!
I think directly you cannot bind a list of objects to your form backing bean, rather you can bind a parent class which contains this list, for example UserForm class contains list of UserAnswer and bind the UserForm as the form backing bean.

Spring MVC - Child entity lost after submit

I'm going to try to explain my problem as completely and shortly as I can...
A web application, made on Spring MVC 2.5 + Hibernate + Java 6 (not using annotation!).
I've got a controller extending SimpleFormController and a jsp page that is its formView and successView.
This controller should help me to insert into db an entity PracticeT that has connected (many to one) a lookup entity PracticeConfT (think about it as a "typology"). I need to choose that "typology" through a drop-down menu. In my webapp I need to be able to save data inserted and when I want, to submit the request for approval.
The page has some text fields and that drop-down menu. The bean called as default "command" is NewPracticeBean that has within a reference to an object PracticeT.
THE PROBLEM IS: I fill the form, I select a typology from the drop-down menu, I submit form and save data on DB but when I come back to the view, every property is there but the drop-down menu it is not: it has all the options allowed but no one selected. Some checks revealed that the entity PracticeConfT is null (but it has been recorded on db correctly and debugging it is still there in the model until the very end of the method onSubmit!!!).
I hope someone can help me. Thank you in advance!
Bye,
Dolfiz
Here some useful code:
(I don't think that hibernate config can be the problem, but if you need it, I can post it too)
newPractice.jsp
<form:form id="newPracticeForm" commandName="command">
<input type="hidden" name="action"/>
<spring:nestedPath path="practiceT">
<table class="table-data-form">
<tr>
<td class="left"><spring:message code="" text="Practice type" /></td>
<td>
<form:select path="practiceConfT" multiple="false">
<form:option value="" label="- seleziona -"/>
<form:options items="${practiceTypeList}" itemValue="idPracticeConf" itemLabel="practiceName"/>
</form:select>
</td>
</tr>
<tr>
<td class="left">
<spring:message code="" text="Opzione divisa" />
<br/><form:errors cssClass="errors" path="opzioneDivisa" />
</td>
<td><form:input path="opzioneDivisa" /></td>
</tr>
<tr>
<td colspan="1">
<input type="submit" name="submit" id="submit" value="Save" class="buttonEMS" style="width:100px;" />
</td>
</tr>
</table>
</spring:nestedPath>
</form:form>
NewPracticeBean.java
public class NewPracticeBean implements Serializable{
private PracticeT practiceT;
private String action;
private boolean typeSelected;
public NewPracticeBean(){
super();
this.practiceT = new PracticeT();
}
// getters & setters...
}
PracticeT.java
public class PracticeT implements java.io.Serializable {
private long idPractice;
private PracticeConfT practiceConfT;
private String opzioneDivisa;
// getters & setters...
}
PracticeConfT.java
public class PracticeConfT implements java.io.Serializable {
public static final String PRACTICE_NAME = "practiceName";
private long idPracticeConf;
private String practiceName;
// getters & setters...
}
NewPracticeController.java
public class NewPracticeController extends SimpleFormController{
protected SmartLogger log = SmartLogger.getLogger(this.getClass());
private PracticeSu practiceSu;
private ConfigurationSu configurationSu;
private HibernateEntityDataBinder practiceConfTBinder;
private HibernateEntityDataBinder practiceTBinder;
public NewPracticeController() {
setCommandClass(NewPracticeBean.class);
setCommandName("command");
}
#Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
log.trace("NewPracticeController -- initBinder");
super.initBinder(request, binder);
binder.registerCustomEditor(PracticeT.class, "practiceT", practiceTBinder);
binder.registerCustomEditor(PracticeConfT.class, "practiceT.practiceConfT", practiceConfTBinder);
}
#Override
protected Map referenceData(HttpServletRequest request) throws Exception {
log.trace("NewPracticeController -- referenceData");
Map model = new HashMap();
RetrieveAllEntitiesReq req = new RetrieveAllEntitiesReq();
req.setEntity(PracticeConfT.class);
req.setOrderProperty(PracticeConfT.PRACTICE_NAME);
RetrieveAllEntitiesResp resp = configurationSu.retrieveAllEntities(req);
List entitiesList = resp.getEntitiesList();
model.put("practiceTypeList", entitiesList);
return model;
}
#Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception {
NewPracticeBean practiceBean = (NewPracticeBean)command;
Map model = errors.getModel();
CreateNewPracticeReq req = new CreateNewPracticeReq();
req.setPracticeT(practiceBean.getPracticeT());
CreateNewPracticeResp resp = practiceSu.createNewPractice(req);
practiceBean.setPracticeT(resp.getPracticeT());
model.putAll(referenceData(null));
model.put(getCommandName(), practiceBean);
return new ModelAndView(getSuccessView(), model);
}
// setters and getters...
}
After spending some time with OptionsTag, OptionWriter and SelectValueComparator, I would say, then output of "selected" is based on Object.equals.
So if for any reason (Lazyloading...) the Object PracticeT.practiceConfT and the according Objects of model.put("practiceTypeList", entitiesList) are not the SAME (==) then forms:options will not select them as long as the equals method is not correct implemented.
So I guess you need to implement a correct equals method, even if this did not fix this problem, it is always better to have a correct equals method than a wrong or none.
Correct implemented means that it must pay attention to the fact that is used with Hibernate. (for example use if (Hibernate.getClass(this) != Hibernate.getClass(other)) instead of `if (this.getClass() != other.getClass() )

Categories