Spring MVC - Child entity lost after submit - java

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

Related

#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}"/>

JSP set boolean value in form

I have a Model:
public class Header {
private Boolean SERVICE;
}
Controller:
#RequestMapping("mymodel/Edit")
public ModelAndView mymodelEdit(
#ModelAttribute("mymodel") Mymodel mymodel,
#RequestParam String id) {
Mymodel old_mymodel = mymodelService.getMymodel(id);
Map<String, Object> map = new HashMap<String, Object>();
map.put("old_mymodel", old_mymodel);
return new ModelAndView("mymodel/mymodelEditView", "map", map);
}
JSP Form
<c:set var="old_mymodel" value="${map.old_mymodel}" />
<form:form method="POST action="/mymodel/Save" modelAttribute="mymodel">
<tr>
<td>Сервис :</td>
<td>
<form:checkbox path="SERVICE" value="${old_mymodel.SERVICE}">
</form:checkbox>
</td>
</tr>
<tr>
<td> </td>
<td><input type="submit" value="Save" /></td>
</tr>
</table>
</form:form>
My problem: I can't set a value from db to form value, i.e. when SERVICE value is true, checkbox is not checked.
The way you are trying to access the model does not correspond to the way you have populated it.
I propose you change your code to:
#RequestMapping("mymodel/Edit")
public ModelAndView mymodelEdit(
#ModelAttribute("mymodel") Mymodel mymodel,
#RequestParam String id) {
Mymodel old_mymodel = mymodelService.getMymodel(id);
return new ModelAndView("mymodel/mymodelEditView", "model", old_mymodel);
}
and
That is assuming that Mymodel looks something like:
public class Mymodel {
private Header old_header;
}
Also there might be some problems with the names you have used in various parts of the model. I strongly suggest that you adhere to JavaBean naming conventions
first thing you are setting the value of map to variable like below
<c:set var="old_header" value="${map.old_mymodel}" />
so you have to access the SERVICE boolean value using this variable not map.
so it should be accessed like below
<td><form:checkbox path="SERVICE" value="${old_header.SERVICE}"></form:checkbox></td>
instead of
<td><form:checkbox path="SERVICE" value="${old_mymodel.SERVICE}"></form:checkbox></td>
where you are using old_mymodel,
assuming below code returns correct model
Mymodel old_mymodel = mymodelService.getMymodel(id);

How do I capture multiple input text fields data into a list and iterate it over using JSTL?

I am trying to do below. In my JSP, I created a table with heading such as "Oct 2013", "Nov 2013", ....for next 12 months. i.e. till "Sept 2014".
These months and years should current, for e.g. if the month is Nov 2013 then the system should detect is Nov 2013 and it should add 12 months till next year Oct 2014.
There are 12 input fields (one for each month), and they are in a single row.
The user can add a new row dynamically in this table and enter can enter quantity values into those text fields for any of the input fields for the months.
<table border="1" class="atable" align="center" width="85%">
<tr>
<th>LRN Required</th>
<th>Oct 2013</th>
<th>Nov 2013</th>
<th>Dec 2013</th>
<th>Jan 2014</th>
<th>Feb 2014</th>
<th>Mar 2014</th>
<th>Apr 2014</th>
<th>May 2014</th>
<th>June 2014</th>
<th>Jul 2014</th>
<th>Aug 2014</th>
<th>Sept 2014</th>
</tr>
<tr>
<td></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
<td><input type="text" size="4"/></td>
</tr>
</table>
I am using Spring MVC and would like to use JSTL for this functionality.
Model class:
public class Forecast {
private int id;
private int quantity;
private String lastUpdatedBy;
private String rateCenter;
.....
getters and setters here...
}
My controller class looks like below...
#Controller
#SessionAttributes("forecastModel")
public class ForecastController extends PasBaseController {
#Autowired
HttpServletRequest request;
protected static Logger log = Logger.getLogger(ForecastController.class);
private static final String FRCST_MODEL = "forecastModel";
#RequestMapping(value="preforecast.do")
public String setUpPreforecast(final Model model, HttpServletRequest req)
{
User user = WebUtil.getSignInUser(req);
ForecastModel forecastModel = new ForecastModel();
log.debug("User Info.");
log.debug(user.getUserId());
log.debug(user.getFullName());
log.debug(user.getPhone());
Long id = (long) 15260;
List<Long> userNpaList = null;
List<String> userOcnList = null;
try{
if(user != null)
{
userNpaList = PasServicesUtils.getAllNpaAssocForUserId(id);
userOcnList = PasServicesUtils.geAllOcnAssocForUserId(id);
model.addAttribute("userNpaList", userNpaList);
model.addAttribute("userOcnList", userOcnList);
forecastModel.setUserNpaList(userNpaList);
forecastModel.setUserOcnList(userOcnList);
model.addAttribute("forecastModel", forecastModel);
}
}catch(Exception e){
log.error("List is NULL");
}
log.debug("Exiting setUpPreforecast() method.");
return PasConstants.PREFORECAST;
}
#RequestMapping(value = {PasConstants.FORECAST})
public String continueFromPreforecast(#ModelAttribute("forecastModel") ForecastModel forecastModel, Errors errors, HttpServletRequest request, final ModelMap modelMap) throws Exception
{
User user = WebUtil.getSignInUser(request);
modelMap.addAttribute("ocn", forecastModel.getOcn());
modelMap.addAttribute("phone", user.getPhone());
modelMap.addAttribute("fax", user.getFax());
modelMap.addAttribute("email", user.getEmail());
modelMap.addAttribute("forecastRptDt", PasDate.displayDayMonthYearFormat2(new PasDate()));
modelMap.addAttribute("npa", forecastModel.getNpa());
List<String> rateCntrAbbrList;
rateCntrAbbrList = PasServicesUtils.getAllRtCntrsAssocForNpa(forecastModel.getNpa());
if(rateCntrAbbrList != null && rateCntrAbbrList.size() > 0)
{
modelMap.addAttribute("rateCntrAbbrList", rateCntrAbbrList);
}
//modelMap.addAttribute("rateCtr", forecastModel.getRtCntrId().
//validateForecastData(forecastModel, errors, user);
if (errors.hasErrors())
{
return PasConstants.PREFORECAST;
}
return PasConstants.FORECAST;
}
#RequestMapping(value = {PasConstants.FORECAST_SUCCESS}, method = RequestMethod.POST)
public String submitForecast(#ModelAttribute("forecastModel") ForecastModel forecastModel, Errors errors, HttpServletRequest request, final ModelMap modelMap) throws Exception
{
/* I am trying to access the months related data i.e. quantiy that user entered through the text fields in the above table. */
ForecastServiceClient.createForecast(forecastModel);
return PasConstants.FORECAST_SUCCESS;
}
My question is, how to capture user entered data into a list and pass it to the the controller class?
Do i need to create a separate class for 12 months and a year?
Do I need to access them using a public List<String> getMonthsAndYear() {..} inside my 'Forecast' class since these months and a current year will be a part of this class only.
How do i iterate through list of months inside the JSP using JSTL? I do not want to use scriplet here.
Please, help me how to approach this problem so that the data entered by the user into input fields can be posted to the controller method for further processing.
Thanks,
Model
public class Forecast {
...
private List<String> sections;
/* getters/setters */
}
controller
#RequestMapping(method = RequestMethod.POST, value = "/test.do")
public String someController(#ModelAttribute Forecast forecast ) {
/* Do whatever with your */
}
John, thanks for your reply. I did some research and found that .... can bind a dynamic list. I modified my controller class, I updated my model class and added a list getter and setter methods as you mentioned above, also, I am now using AutoPopulatingList of spring framework to modify the list and pass it to the JSP via modelMap.addAttribute("forecastMonthsBeanList", forecastModel.getForecastMonthsBeanList()), from Controller method. My issue is,however, on the jsp side, I have this jQuery function which is supposed to create a new row every time it is clicked. i.e. the row contains 12 input text boxes/fields and upon single click it is supposed to create 12 new text boxes in a new row, but, it does not work. I am not sure how to make this jQuery function work with spring:bind when "add row" button is clicked. My 1st row is having 12 input text boxes with default values assigned as '0' from a bean declared as a getter and setter in the model class. Below is my jQuery function and JSP code.
<script type="text/javascript">
$("document").ready(function(){
$(".alternativeRow").btnAddRow({oddRowCSS:"oddRow",evenRowCSS:"evenRow"});
$(".delRow").btnDelRow();
});
</script>
Oct 2013Nov 2013Dec 2013Jan 2014Feb 2014Mar 2014Apr 2014
May 2014June 2014Jul 2014Aug 2014Sept 2014
-----

How can I manage a multidimensional array with Struts Form

I'm using Apache Struts 1.3 to render a grid, whitch is a html form embebed in a .jsp. Something like
<html:form action="/MyController.do?action=processForm">
<html:text property="taxation[0][0]" value="" styleClass="gridInputs"></html:text>
<html:text property="taxation[0][1]" value="" styleClass="gridInputs"></html:text>
...
<html:text property="taxation[10][10]" value="" styleClass="gridInputs"></html:text>
MyController is associated to an ActionForm:
public class MyForm extends ActionForm{
protected String taxation[][]= new String [10][10];
public String[] getTaxation() {
return taxation;
}
public void setTaxation(String[][] taxation) {
this.taxation = taxation;
}
The problem arise when I try to retrieve the information submitted by the form. Whithin MyController.class I've a simple dispatcher action
public class MyController extends DispatchAction {
public ActionForward processForm(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
MyForm myform = (MyForm) form;
// Here i can use the getter method to retrieve an array, but
// myform is already wrong populated from struts
}
return mapping.findForward("stage2");
}
I know I can use a Vector (unidimensional array) and It works just fine, but regrettably I need to follow some specs (and the specs force me to use the class MyForm with a 10x10 matrix...). How would be the right way to populated a two dimensional array using struts?
Thank you for the help!
Struts does not support filling of multidimensional array in Form bean. However, it does handle uni-dimensional array of an object. So as a work around if you can create a class (say MatrixRow) which itself contains an Uni-dimensional array and then you can create an Uni-dimensional array of that object in the form bean. Your new class will be look like
public class MatrixRow {
private String matrixCol[] = new String[10];
/**
* #return the matrixCol
*/
public String[] getMatrixCol() {
return matrixCol;
}
/**
* #param matrixCol the matrixCol to set
*/
public void setMatrixCol(String[] matrixCol) {
this.matrixCol = matrixCol;
}
}
Then in your form bean
private MatrixRow[] arrMatrix = new MatrixRow[10];
/**
* #return the arrMatrix
*/
public MatrixRow[] getArrMatrix() {
return arrMatrix;
}
/**
* #param arrMatrix the arrMatrix to set
*/
public void setArrMatrix(MatrixRow[] arrMatrix) {
this.arrMatrix = arrMatrix;
}
and In your JSP, you can use it something like
<html:form action="biArrayTestAction.do">
<table cellpadding="0" cellspacing="0" width="100%">
<logic:iterate id="matrixRows" name="biArrayTestForm"
property="arrMatrix" indexId="sno"
type="logic.MatrixRow" >
<tr>
<td><bean:write name="sno"/></td>
<logic:iterate id="matrixCol" name="matrixRows" property="matrixCol" indexId = "colNo">
<td>
<input type="text" name="arrMatrix[<%=sno %>].matrixCol[<%=colNo %>]">
</td>
</logic:iterate>
</tr>
</logic:iterate>
<tr>
<td align="center" valign="top" colspan="2">
</td>
</tr>
<tr>
<td align="center" valign="top" colspan="2">
<html:submit property="command" value="Test"></html:submit>
</td>
</tr>
</table>
When you submit that form you will get all columns of MatrixRow object filled with the values.
I hope this will help you. I don't find any other way of using multidimensional array in Struts1.

Manually handle error validation in Spring annotated controller

I'm trying to update a Spring controller to use annotations for a relatively simple 'change password' page. The only fields on the page are 'password' and 'confirm password'. When the form is submitted, it calls to a webservice to do the actual changing of the password. That webservice may return a InvalidPasswordException based upon password rules run within that service. So I want to catch the exception, then add an error message to the view to show up next to the 'password' field. The velocity code is already written using #springShowErrors, so I want to add the error in a way that in can be read in by that tag.
Here is my controller:
#Controller
#RequestMapping("/edit-password.ep")
public class EditPasswordFormControllerImpl {
#Autowired
private CustomerService customerService;
#Autowired
private CustomerSessionService customerSessionService;
#RequestMapping(method = RequestMethod.POST)
protected ModelAndView onSubmit(#ModelAttribute("editPasswordFormBean") EditPasswordFormBeanImpl editPasswordFormBean, BindingResult errors, HttpServletRequest request) throws EpWebException {
String nextView = "redirect:/manage-account.ep";
final CustomerSession customerSession = (CustomerSession) request.getSession().getAttribute(WebConstants.CUSTOMER_SESSION);
final Customer customer = customerSession.getShopper().getCustomer();
try {
CustomerInfo customerInfo = new CustomerInfo();
customerInfo.setCustomerId(customer.getUserId());
customerInfo.setPassword(editPasswordFormBean.getPassword());
UpdateAccountServiceRequest updateRequest = new UpdateAccountServiceRequest();
updateRequest.setClientId(CLIENT_ID);
updateRequest.setCustomerInfo(customerInfo);
//this is the webservice call that could throw InvalidPasswordException
customerService.updateUserAccount(updateRequest);
} catch (InvalidPasswordException e) {
// This is where I'm not sure what to do.
errors.addError(new ObjectError("password", e.getMessage()));
nextView = "edit-password.ep";
} catch (ServiceException e) {
throw new EpWebException("Caught an exception while calling webservice for updating user", e);
}
return new ModelAndView(nextView);
}
#RequestMapping(method = RequestMethod.GET)
protected String setupForm(ModelMap model) {
EditPasswordFormBean editPasswordFormBean = new EditPasswordFormBeanImpl();
model.addAttribute("editPasswordFormBean", editPasswordFormBean);
return "account/edit-password";
}
}
And here is a snippet of my velocity template:
<fieldset>
<legend>#springMessage("editPassword.editPasswordTitle")</legend>
<table border="0" cellspacing="0" cellpadding="3">
<colgroup>
<col width="150">
<col width="*">
</colgroup>
<tr>
<td colspan="2">
<br />
<strong>#springMessage("editPassword.changePassword")</strong>
</td>
</tr>
<tr>
<td align="right">#springMessage("editPassword.password")</td>
<td>
#springFormPasswordInput("editPasswordFormBean.password" "maxlength='100'")
#springShowErrors("<br>" "req")
</td>
</tr>
<tr>
<td align="right">#springMessage("editPassword.confirmPassword")</td>
<td>
#springFormPasswordInput("editPasswordFormBean.confirmPassword" "maxlength='100'")
#springShowErrors("<br>" "req")
</td>
</tr>
</table>
</fieldset>
I'm not quite sure what I should do when I catch the exception. What I currently have doesn't work. It returns to the edit-password page, but no error displays. I've read about HandleExceptionResolver, but even if I use that, I'm still not sure how to get the error to display on the view.
Any help is greatly appreciated!
Jeff, its just a guess, if you see the controller you have the RequestMapping("/edit-password.ep"), so when there is an error scenario your next view is "edit-password.ep", so it will come to this controller and it will be consdiered as a get request to the controller. But in your GET mapping method you are always creating a new EditPasswordBean and sending back to the back. If you run the server in debug mode and keep a break point in setUpForm method you will why the errors have been swallowed. Try to give specific mappings for get and post to avoid such issues. Ideally you should a Validator defined and it should be registered in your initBinder method. Check out this link http://static.springsource.org/spring/docs/current/spring-framework-reference/html/validation.html
Hope it helps.

Categories