Multiple Objects of pojo class in 1 html form spring mvc? - java

i am working with Spring where my form fields are same with attribute fields so when i submit form it directly maps to database fields and save the data it works perfectly, but what if i want to save multiple objects with one form,
HTML:
<form>
Payment:<br>
<input type="text" name="payment"><br>
Date:<br>
<input type="date" name="paymentDate">
</form>
POJO:
public class ProjectPayment
{
private Double payment;
private Date paymentDate;
// setters and getters
}
Controller:
#RequestMapping(value = "/addnewproject", method = RequestMethod.POST)
public #ResponseBody String SaveProject(ProjectPayment projectPayment) {
projectPaymentService.saveProjectPayment( projectPayment);
}
this works perfectly,
but now in my some scenario i need multiple objects dynamically then how to save in database, how controller should look like
for example:
Now my Form is
<form>
Payment:<br>
<input type="text" name="payment"><br>
Date:<br>
<input type="date" name="paymentDate">
Payment:<br>
<input type="text" name="payment"><br>
Date:<br>
<input type="date" name="paymentDate">
Payment:<br>
<input type="text" name="payment"><br>
Date:<br>
<input type="date" name="paymentDate">
Payment:<br>
<input type="text" name="payment"><br>
Date:<br>
<input type="date" name="paymentDate">
</form>
Now this form have multiple objects of ProjectPayment class but it saves only one object
please tell me how my controller should like, i have done like this but it occurs exception
Controller:
#RequestMapping(value = "/addnewproject", method = RequestMethod.POST)
public #ResponseBody String SaveProject(ProjectPayment[] projectPayment) {
for(ProjectPayment propay : projectPayment)
{
projectPaymentService.saveProjectPayment( propay );
}
}

I can understand that you want to post data from a grid/table, however it's too ambiguous to determine which field map to which object.
Example:
field1
field2
field3 ==>Map to object at index 1 or 2?
filed1
So you think field3 should map to array index=1 or index=2?
So I suggest you should submit one by one to solve this issue.

Simple way to solve this problem is create a ViewModel.
e.g.
public class ProjectPaymentViewModel
{
private List<ProjectPayment> listProjectPayment;
// setters and getters
}
Use this view model on web page and controller
<form>
Payment:<br>
<input type="text" name="listProjectPayment[0].payment"><br>
Date:<br>
<input type="date" name="listProjectPayment[0].paymentDate">
Payment:<br>
<input type="text" name="listProjectPayment[1].payment"><br>
Date:<br>
<input type="date" name="listProjectPayment[1].paymentDate">
Payment:<br>
</form>
On controller
#RequestMapping(value = "/addnewproject", method = RequestMethod.POST)
public #ResponseBody String SaveProject(ProjectPaymentViewModel projectPaymentViewModel) {
for(ProjectPayment propay : projectPaymentViewModel.getListProjectPayment())
{
projectPaymentService.saveProjectPayment( propay );
}
}

Related

Thymeleaf concatenates values of input fields where the attribute names of the objects are identical [duplicate]

I'm asking for help because thymeleaf does somthing weird:
Here is my form:
<form action="#" th:action="#{/add-new-board}" method="post">
<p>Board name: <input type="text" th:name="board" th:field="${board.name}" /></p>
<p th:if="${#fields.hasErrors('board.name')}" th:errors="${board.name}">Name Error</p>
<p>Section #1 name: <input type="text" th:name="section" th:field="${section.name}" /></p>
<p th:if="${#fields.hasErrors('section.name')}" th:errors="${section.name}">Name Error</p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
Here is my controller:
#GetMapping(path = "/add-new-board")
public String addNewBoardForm(Model model) {
model.addAttribute("board", new Board());
model.addAttribute("section", new Section());
return "fragments/forms/add-new-board";
}
#PostMapping(path = "/add-new-board")
public String addNewBoardSubmit(#Valid #ModelAttribute Board board,
#Valid #ModelAttribute Membership membership,
#Valid #ModelAttribute Section section,
#AuthenticationPrincipal UserDetailsImpl principal,
BindingResult result,
RedirectAttributes attributes) {
if (result.hasErrors()) {
attributes.addFlashAttribute("create_board_fail", "Check if you have all fields");
return "fragments/forms/add-new-board";
} else {
board.setCreated_at(LocalDateTime.now());
Slugify slug = new Slugify();
board.setSlug(slug.parse(board.getName()));
boardRepository.save(board);
User user = userRepository.findByEmail(principal.getEmail()).get();
membership.setMember_type(MemberType.MANAGER);
membership.setBoardId(board);
membership.setUserId(user);
membershipRepository.save(membership);
section.setBoard(board);
section.setColor(ColorType.BLUE_BASIC);
section.setOrdering(1);
sectionRepository.save(section);
attributes.addFlashAttribute("create_board_success", "You successfully added a new board!");
return "redirect:/";
}
So, my goal is to insert text from 1st input to "board" table to a column "name", and insert text from 2nd input to "section" table to a column "name". So this column titles are similar. Now when I run code, fill inputs and submit it, I'm getting to my database:
database tables img
Where "AAA" is what I wrote in 1st input, and "BBB" in 2nd
This is happening because you are using th:field incorrectly. th:field is designed to be used with a single th:object but right now you are using 2 different objects board and section. When the HTML is rendered, both inputs probably have the same name="name" and when that is submitted, the values are concatenated together and you get the behavior you are seeing.
You should instead add Board and Section to a single object, and use that as your form. For example, if you created a BoardForm object:
public class BoardForm {
private Board board = new Board();
private Section section = new Section();
// Getters and setters...
}
added that to your model instead
model.addAttribute("form", new BoardForm());
then your html would look like this
<form action="#" th:action="#{/add-new-board}" th:object="${form} method="post">
<p>Board name: <input type="text" th:name="board" th:field="*{board.name}" /></p>
<p>Section #1 name: <input type="text" th:name="section" th:field="*{section.name}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>

Thymeleaf retrieving text from input with similar field name adding it to another separated by comma

I'm asking for help because thymeleaf does somthing weird:
Here is my form:
<form action="#" th:action="#{/add-new-board}" method="post">
<p>Board name: <input type="text" th:name="board" th:field="${board.name}" /></p>
<p th:if="${#fields.hasErrors('board.name')}" th:errors="${board.name}">Name Error</p>
<p>Section #1 name: <input type="text" th:name="section" th:field="${section.name}" /></p>
<p th:if="${#fields.hasErrors('section.name')}" th:errors="${section.name}">Name Error</p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
Here is my controller:
#GetMapping(path = "/add-new-board")
public String addNewBoardForm(Model model) {
model.addAttribute("board", new Board());
model.addAttribute("section", new Section());
return "fragments/forms/add-new-board";
}
#PostMapping(path = "/add-new-board")
public String addNewBoardSubmit(#Valid #ModelAttribute Board board,
#Valid #ModelAttribute Membership membership,
#Valid #ModelAttribute Section section,
#AuthenticationPrincipal UserDetailsImpl principal,
BindingResult result,
RedirectAttributes attributes) {
if (result.hasErrors()) {
attributes.addFlashAttribute("create_board_fail", "Check if you have all fields");
return "fragments/forms/add-new-board";
} else {
board.setCreated_at(LocalDateTime.now());
Slugify slug = new Slugify();
board.setSlug(slug.parse(board.getName()));
boardRepository.save(board);
User user = userRepository.findByEmail(principal.getEmail()).get();
membership.setMember_type(MemberType.MANAGER);
membership.setBoardId(board);
membership.setUserId(user);
membershipRepository.save(membership);
section.setBoard(board);
section.setColor(ColorType.BLUE_BASIC);
section.setOrdering(1);
sectionRepository.save(section);
attributes.addFlashAttribute("create_board_success", "You successfully added a new board!");
return "redirect:/";
}
So, my goal is to insert text from 1st input to "board" table to a column "name", and insert text from 2nd input to "section" table to a column "name". So this column titles are similar. Now when I run code, fill inputs and submit it, I'm getting to my database:
database tables img
Where "AAA" is what I wrote in 1st input, and "BBB" in 2nd
This is happening because you are using th:field incorrectly. th:field is designed to be used with a single th:object but right now you are using 2 different objects board and section. When the HTML is rendered, both inputs probably have the same name="name" and when that is submitted, the values are concatenated together and you get the behavior you are seeing.
You should instead add Board and Section to a single object, and use that as your form. For example, if you created a BoardForm object:
public class BoardForm {
private Board board = new Board();
private Section section = new Section();
// Getters and setters...
}
added that to your model instead
model.addAttribute("form", new BoardForm());
then your html would look like this
<form action="#" th:action="#{/add-new-board}" th:object="${form} method="post">
<p>Board name: <input type="text" th:name="board" th:field="*{board.name}" /></p>
<p>Section #1 name: <input type="text" th:name="section" th:field="*{section.name}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>

creating 2 model attributes of same object and parsing them to controller with #RequestMapping

Im trying to create 2 instances of an object and then parse them to the controller via an input type="submit".
Here's what I have:
#RequestMapping (value = "/webdata")
public String vorsorgestammdaten(Model model) {
model.addAttribute("Data", new DataOp());
model.addAttribute("Data2", new DataOp());
return "/webdata";
}
// Here I want to parse both objects
#RequestMapping(value = "/formdata", method = RequestMethod.POST)
public String formdata(HttpServletRequest req, #AuthenticationPrincipal User currentUser,
DataOp Data, DataOp Data2, Model model) {
// Do stuff for example
Data.getName();
Data2.getName();
}
Here is part of my forms:
<form method="post" th:action="#{/formdata}" th:object="${regData}">
<div class="col-sm-4">
<input th:field="${Data2.gender}" type="radio" value="MALE" name="gender" disabled="disabled" /><span>Mr</span>
<input th:field="${Data2.gender}" type="radio" value="FEMALE" name="gender" disabled="disabled"/><span>Frau</span>
<p>Firstname:</p>
<input required="required" type="text" th:field="${Data2.firstname}" placeholder="Max" disabled="disabled" />
</div>
<div class="col-sm-4">
<input th:field="*{Data.gender}" type="radio" value="MALE" name="gender" disabled="disabled" /><span>Mr</span>
<input th:field="*{Data.gender}" type="radio" value="FEMALE" name="gender" disabled="disabled"/><span>Frau</span>
<p>Firstname:</p>
<input required="required" type="text" th:field="*{Data.firstname}" placeholder="Max" disabled="disabled" />
<button type="submit">Speichern</button>
</div>
</form>
Try removing this th:object="${regData}".
Then you can use #ModelAttribute annotation.
For example,
public String formdata(HttpServletRequest req,#AuthenticationPrincipal User currentUser, #ModelAttribute DataOp Data,#ModelAttribute DataOp Data2, Model model) {
//Some code
}
You might as well switch *{Data.gender} to ${Data.gender}.
add RequestAttribute annotation to each of those params, adding the "name" attribute to differentiate them.
here you have some info.

Unable to bind values to input box on Jsp page in angular

I used angular in my jsp page but I'm confused how to bind values to inputbox
Here My is my Controller
#RequestMapping(value="/customer" , method = RequestMethod.GET)
public String getCustomerPage(Model model,HttpSession session){
CustomerBean customerBean = getCustomerById(id);
model.addAttribute("customer", customerBean);
return "addCustomer"
}
My jsp code
<input type="text" name="customerName" value="${customer.name}" ng-model="cust.name" required/>
Unable to bind value
But if i removed ng-model then value bind to control
i.e
<input type="text" name="customerName" value="${customer.name}" required/>
this works
Help!

How to retrieve form elements at controller in java

I am trying to submit a form to controller in using java spring, in following code i am retrieving file element by following way successfully but not getting how to retrieve other elements(shortname and full name)value.
please help me out.
<body>
<div style="text-align: center; margin-top: 60px;">
<form action="upload" enctype="multipart/form-data">
<input type="hidden" id="shortName" name="michael">
<input type="hidden" id="fullName" name="michael jackson">
Select file:
<input type="file" name="dataFile" id="fileAttachment"/><br/><br/>
<div style="text-align: center; margin-top: 100px;">
<input style="cursor: pointer;" onmouseover="" onclick="uploadAttachment()" class="dialogbox" type="submit" value="Upload Report" />
</div>
</form>
</div>
</body>
Controller side code :
#RequestMapping(value = "upload", method=RequestMethod.POST)
public void upload(HttpServletRequest request, HttpServletResponse response,
#RequestPart("dataFile") MultipartFile file
){
System.out.println(file.getSize());
}
first change the input elements and create the name attribute for both shortName and fullName like so :
<input type="hidden" id="shortNameId" name="shortName" value="michael">
<input type="hidden" id="fullNameId" name="fullName" value="michael jackson">
however you can remove the default value attribute and just enter the value yourself when the page render so value="michael" & value="michael jackson" are optional !
Then you can retrieve those input elements like this :
#RequestMapping(value = "upload", method=RequestMethod.POST)
public void upload(HttpServletRequest request, HttpServletResponse response, #RequestParam("shortName")String shortName, #RequestParam("fullName")String fullName
#RequestPart("dataFile") MultipartFile file
){ .... }
Good Luck !
In your controller, try something like this,
#RequestMapping(value = "/your/url/{formParamenter}", method = RequestMethod.GET)
public String yourfunction(#PathVariable("formParameter") Type formParameter{}
The Type is the type of data, (String/int/float..etc).
In your case just change RequestPart to #PathVariable

Categories

Resources