Passing Model Object as #RequestParameter to Spring Controller - java

I have a JSP page that displays list of employees found.
<c:forEach items="${employeeList}" var="employee">
<div class="formRow" style="background-color: red">
<div class="employeeResultColumnSmall">${employee.getEmpNo()}</div>
<div class="employeeResultColumnRegular">${employee.getFirstName()}</div>
<div class="employeeResultColumnRegular">${employee.getLastName()}</div>
<div class="employeeResultColumnSmall">${employee.getGender()}</div>
<div class="employeeResultColumnRegular">${employee.getDateOfBirth()}</div>
<div class="employeeResultColumnRegular">${employee.getHireDate()}</div>
<div class="employeeResultColumnRegular">${employee.getDept().getDeptName()}</div>
<div class="employeeResultColumnSmall">Update</div>
</div>
</c:forEach>
Controller
#RequestMapping(value = "/updateemployee", method = RequestMethod.GET)
public ModelAndView goUpdateEmployee(#RequestParam("employee") Employee employee){
System.out.println(employee);
return null;
}
I want to pass the employee bean to a controller whose update link is clicked. I tried doing it as shown above but not working.

Related

#ModelAttribute return null thymeleaf

I familiarize myself with Thymeleaf.
I am trying to get data from a POST-mapping in the controller.
But I got null variables when I call employee.getName().
I looked a lot online but can't find a solution.
My controller class
#GetMapping
public String getEmployees(Model model) {
model.addAttribute("newEmployee", new Employee());
return "employees";
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null
return "employees";
}
HTML form with Thymeleaf
<div class="modal-body">
<form th:action="#{/employees}" th:object="${newEmployee}" method="post">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">First Name <span class="text-danger">*</span></label>
<input th:field="*{firstName}" class="form-control" type="text">
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label class="col-form-label">Last Name</label>
<input th:field="*{lastName}" class="form-control" type="text">
</div>
</div>
See tutorials:
Wim Deblauwe: Form handling with Thymeleaf
Baeldung: Binding a List in Thymeleaf
#GetMapping("/all")
public String showAll(Model model) {
model.addAttribute("employees", employeeService.findAll());
return "employees/all";
}
#GetMapping("/add")
public String createForm(Model model) {
model.addAttribute("newEmployee", new Employee()); // the form-data object as blank employee to be filled
return "employees/form"; // the page containing the form
}
#PostMapping
public String addEmployee(#ModelAttribute("newEmployee") Employee employee) {
System.out.println(employee); // return object
System.out.println(employee.getFirstName()); // return null if either not set in HTML-form or not mapped from HTML-form to POST correctly
// save new employee or add to a repository
employeeService.save(newEmployee);
model.addAttribute("employees", employeeService.findAll());
return "redirect:/employees/all"; // use a redirect
}
Client-Server interaction:
First in your browser you should navigate to the endpoint adding the form-data-object, i.e. GET /employees/add.
Then the form-page should load and you will have a blank object newEmployee to bind all the input-fields to for submitting.
After submitting the form via the submit-click, a POST /employees is sent. The server/controller should receive the form-data as model-attribute in employee parameter and can save it.
The controller-method redirects back to the list-endpoint (same as navigating in browser to) GET /employees/all
<h1>Create employee</h1>
<form th:object="${newEmployee}"
th:action="#{/employees}"
method="post">
<input type="text" name="firstName" id="firstName" th:field="*{firstName}" />
<input type="text" name="lastName" id="lastName" th:field="*{lastName}" />
<button type="submit">Submit new employee</button>
</form>
The th:object attribute refers to the key under which we put our Employee instance in the model (newEmployee in this example). The th:action has the URL for the #PostMapping method. Finally, the method attribute is set to "post" since we want to use the HTTP POST method.
Using th:field=*{…​}, we can setup a two-way binding between the HTML input and the field in our form data object.

Thymeleaf - populate dropdown menu from object list

Currently, the methods return only their own links into the required fields, ie. the last html element for available tests returns only availableTestList in the div that is supposed to list all available tests. Same for "/currentTest" and for the dropdown menu, which shows no options at all.
I started trying some fixes from here on SO, and now my html broke down completely, giving me the error:
An error happened during template parsing (template: "templates/Teacher.html")
and in java console:
"Neither BindingResult nor plain target object for bean name 'test' available as request attribute"
Any ideas?
Below is the controller code first, with the html afterwards.
#Controller
public class TeacherController {
TestController testcont = TestController.getInstance();
#RequestMapping(value = "sendTest", method = RequestMethod.POST)
public String sendTest(Model model) throws IOException, ServletException{
for(Test test : testcont.showAllTests()){
if(test.getName().equals("selection")){
testcont.SetActiveTest(test);
System.out.println(testcont.getActiveTest());
//return "Test sent successfully to students! <a href='/Teacher'>Back</a>";
}
}
model.addAttribute("tests", testcont.showAllTests());
return "sendTest";
}
#RequestMapping(value = "resetCurrentTest", method = RequestMethod.POST)
public String resetCurrentTest(Model model){
testcont.SetActiveTest(null);
model.addAttribute("tests", testcont.showAllTests());
return "resetCurrentTest";
}
#RequestMapping(value = "currentTestOptions", method = RequestMethod.GET)
//#ModelAttribute("/currentTestOptions")
//#GetMapping("/currentTestOptions")
public String currentTestOptions(Model model) {
model.addAttribute("tests", testcont.showAllTests());
return "currentTestOptions";
}
#RequestMapping(value = "getActiveTest", method = RequestMethod.GET)
public String getActiveTest(){
return testcont.getActiveTest().toString();
}
}
The HTML
<body>
<p>
<a href='/Teacher/NewTest'>New Test upload</a>
</p>
<div
style='height: 150px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<form th:action='${sendTest}' th:object="${tests}" method='post'>
<fieldset>
<label>Select test</label>
<select id="tests" name="tests" class="form-control" th:field="${tests}">
<option value="">Select test</option>
<option
th:each="test : ${tests}"
th:value="${test.getName}"
th:text="${test.getName}"
></option>
</select>
</fieldset>
<input type='submit' value='Submit'>
</form>
</div>
<form action='${resetCurrentTest}' method='post'>
<input type='submit' value='Clear'>
</form>
<a> Current Test for students: </a>
<p th:text="${getActiveTest}" ></p>
<p>All available tests on server:</p>
<div
style='height: 200px; width: 400px; border: 1px solid #ccc; font: 16px/26px Georgia, Garamond, Serif; overflow: auto;'>
<th:block th:each="test : ${tests}">
</div>
</body>
in the controller, the 3rd method "currentTestOptions" is supposed to return the full list of objects, and in the HTML I am to iterate through the list using test : currentTestOptions, and then as the value retrieve the test names to show in the dropdown.
Current console error when trying to open the local page /Teacher is:
Neither BindingResult nor plain target object for bean name 'test' available as request attribute
try this code
<option th:each="test : ${currentTestOptions}"
th:value="${test.getName}"
th:text="${test.getName}"></option>
for more thymeleaf-forum/Create-drop-down-list
thymeleaf-select-option
Bolow is my controller code:
ModelAndView view = new ModelAndView("view/index");
UserIdentity userIdentity = (UserIdentity) request.getSession().getAttribute(SessionConstant.ACCOUNT_SESSION_KEY);
if(userIdentity == null){
return null;
}
List<PayBill> payBills = payBillService.getBillDetailByUserId(userIdentity.getId());
if(payBills != null && payBills.size() > 0){
view.addObject("bill",payBills.get(0));
}
return view;
Bolow is my html code:
<div class="centerBox">
<div class="centerBox1" th:if="${bill != null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;" th:text="${bill.paymentAmount}">100.00</p>
</div>
<div class="centerBox1" th:if="${bill == null}">
<p style="color:#999;">当月水费金额</p>
<p style="color:red;font-size:40px;">0.00</p>
</div>
<button type="button" onclick="btn()" class="mui-btn mui-btn-primary" style="width: 100%;border-radius: 20px;margin:30px 0px 10px 0px" data-loading-icon="mui-spinner mui-spinner-custom" >立即缴费</button>
<p>往期水费记录</p>
<!-- image -->
<div class="bottomBox">
<img src="/images/bottom.png" width="100%" alt="" />
</div>
</div>
Attention please, use this code th:if="${bill != null} to avoid get a null value. if it's null, it giving me the error.
In html file you have:
<select class="form-control" th:field="${test.getName}">
Thymeleaf expects that you will pass attribute called test through model. You can do it like this:
model.addAttribute("test", yourObjectRepresentingTest);
Do this in a controller method that returns view to your html. For example:
#GetMapping("/showTests")
public String showTests(Model model) {
// some controller logic if you need
SampleTest sampleTest = new SampleTest(); // <- this is your backing bean object that will be bound to thymeleaf view
model.addAttribute("test", sampleTest);
return "showtests"; // <- this is a file name of a html containing your view
}
You may also need to add th:object to your html file:
<form th:action="#{/sendTest}" th:object="${test}" method='post'>

I can't pass th:object to controller and mapped to pojo using #ModelAttribute

I am trying to retrieve object on my controller that mapped to my POJO
My POJO looks like this
public interface InventoryDetailPOJO {
String getItem_cd();
}
And this is my form
<div class="row d-flex">
<div class="p-3">
<button class="btn btn-block btn-options btn-save">Save</button>
</div>
</div>
<form action="#"
th:action="#{/stock-list/inventory-detail}"
method="post"
th:object="${inventoryDetail}"
class="pt-3 form-inventory-detail">
<div class="form-group row">
<label for="item_cd" class="col-2 col-form-label col-form-label-sm">
<span class="pull-right">Item No</span>
</label>
<div class="col-10">
<input type="text" class="form-control form-control-sm w-25"
th:field="*{item_cd}">
</div>
</div>
</form>
And for my controller
#RequestMapping(value = "/stock-list/inventory-detail", method = RequestMethod.POST)
public ModelAndView InventoryDetailSubmitPage(ModelAndView modelAndView,
#ModelAttribute("inventoryDetail") InventoryDetailPOJO inventoryDetail,
#RequestParam("item_cd") String item_cd) {
System.err.println("InventoryDetail: " + inventoryDetail);
System.err.println("item_cd: " + item_cd);
modelAndView.setViewName("redirect:/stock-list");
return modelAndView;
}
There're no item on inventoryDetail when I tried to log it, but There's a value on item_cd
Remove action="#", like this:
<form th:action="#{/stock-list/inventory-detail}"
method="post"
th:object="${inventoryDetail}"
class="pt-3 form-inventory-detail">

spring return object on button click out of list

Hi guys hope you can help me, because i cant get further at the moment
I have my Controller.
#RequestMapping(value="/kundenseite", method= RequestMethod.GET)
public String kundenLogin(ModelMap model) {
if(kundeComponent.getKunde() != null) {
List<Restaurant> restaurants = restaurantService.alleRestaurants();
model.addAttribute("restaurants", restaurants);
return "kundenseite";
}else {
return "redirect:/kunde/login";
}
}
#RequestMapping(value="/kundenseite", method= RequestMethod.POST)
public String kundenLoginAnswer(ModelMap model, #ModelAttribute Restaurant restaurant) {
System.out.println(restaurant.toString());
return "kundenseite";
And my jsp file
<%# include file="common/header.jspf" %>
<div class="jumbotron text-center">
<h1>MiMiMi Lieferservice</h1>
<p>Der schnellste Lieferservice von Passpick</p>
</div>
<div style="margin-right:auto; margin-left:auto; width: 33%">
<h2 style="text-align: center">Restaurant wählen</h2>
<div class="well">
<c:forEach items="${restaurants}" var="restaurant">
<form:form modelAttribute="${restaurant}" method="post">
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.name}</div>
<div style="margin-top: 8px" class=col-sm-4 >${restaurant.restaurantTyp}</div>
<button type="submit">Bestellen</button>
</form:form>
<br style="clear:both;" />
</c:forEach>
</div>
</div>
</body>
</html>
If the user presses a button i want to return a restaurant.
But i don't know how to make that happen, my thought was to use a form but i cant get it to send a complete restaurant object back
If there is no solution for this i have to write the id with the button.
You need input hidden inside the form tab as below input hidden:
<input type="hidden" name="name" value="${restaurant.name}">
<input type="hidden" name="restaurantTyp" value="${restaurant.restaurantTyp}">

How to hold filter parameters. Pagination

I have some problem with search filter and pagination. Filter works good, but i can't say the same about pagination.
I have a table with users. I can show all users or by filter(by name, by email). When i'm using filter and trying to go to second page, it return all users without filtration. I understand why it happens, because has no filter parameters. Help me find solution. How can i hold selected filters? Something with sessions?
Here my code.
My Controller
#Controller
#RequestMapping(value = "/admin")
public class AdminController {
#Autowired
UserService userService;
#RequestMapping(value = "/edit-user", method = RequestMethod.GET)
public ModelAndView editUsers(#RequestParam(value = "page", defaultValue = "0") Integer page,
#RequestParam(value = "pattern", required = false) String pattern,
#RequestParam(value = "category", required = false) String category) {
ModelAndView view = new ModelAndView("edit-user");
if(pattern == null){
Page<User> userList = userService.findAll(page);
view.addObject("userList", userList.getContent()).addObject("maxPage", userList.getTotalPages());
}else if(category.equals("username")){
Page<User> userList = userService.findByUsernameContaining(pattern, page);
view.addObject("userList", userList.getContent()).addObject("maxPage", userList.getTotalPages());
}else {
Page<User> userList = userService.findByEmailContaining(pattern, page);
view.addObject("userList", userList.getContent()).addObject("maxPage", userList.getTotalPages());
}
return view;
}
}
My part of JSP
<div class="row top-buffer">
<div class="col-md-4 col-md-offset-4">
<form class="form-inline text-center" role="form" method="get" action="/admin/edit-user?pattern=pattern?category=category">
<fieldset>
<!-- Search Name -->
<div class="form-group">
<label class="sr-only" for="item-name">Product Name</label>
<input id="item-name" name="pattern" placeholder="..." class="form-control">
</div>
<!-- Search Category -->
<div class="form-group">
<label class="sr-only" for="item-category">Product Category</label>
<select id="item-category" name="category" class="form-control">
<option value="username" selected>By username</option>
<option value="email">By email</option>
</select>
</div>
<!-- Search Action -->
<div class="form-group">
<button type="submit" class="btn btn-primary"><span
class="glyphicon glyphicon-search" aria-hidden="true"></span></button>
</div>
</fieldset>
</form>
</div>
</div>
<div class="row top-buffer">
<div class="col-md-8 col-md-offset-2">
<table class="table">
<thead>
<th>Id</th>
<th>Username</th>
<th>Email</th>
<th>Password</th>
</thead>
<c:forEach var="user" items="${userList}">
<tr>
<td>${user.id}</td>
<td>${user.username}</td>
<td>${user.email}</td>
<td>${user.password}</td>
<td>
<button type="button" class="btn btn-info btn-sm editButton" data-toggle="modal"
data-target="#myModal" data-id="${user.id}">Edit
</button>
</td>
</tr>
</c:forEach>
</table>
</div>
</div>
<div class="row">
<div class="col-md-4 pull-right">
<ul class="pagination">
<c:forEach begin="0" end="${maxPage - 1}" var="i">
<li>${i+1}</li>
</c:forEach>
</ul>
</div>
</div>
In your case, putting filter information in session should be OK. You can create a Filter enum that has e.g. name, email fields. Store/update a Filter instance in session every time user wants to filter something.
You can attach your filters to your link(page number in your case) as a query string like so:
${i+1}
In your controller, you need to get the filter information and handle it accordingly (get the value of param filterby, which is name or email). If the filterby param has no value, then no filter is chosen.

Categories