i want to create a form in which user can set name, age, birthday and department which is another object..
in jsp i already have the form with the inputs of name, age and birthday. For department i already create the select/option tag with the results from hibernate/db.
The problem is when i sumbit and post the the mployee i have a lot of erros
#RequestMapping(value = { "/new" }, method = RequestMethod.POST)
public String saveEmployee(#Valid #ModelAttribute Employee employee,
#PathVariable("department") int department, BindingResult result,
ModelMap model) {
jsp file
<tr>
<td>
<select name="department">
<c:forEach var="dep" items="${departments}">
<option value="${dep.id}">${dep.name}</option>
</c:forEach>
</select>
</td>
</tr>
i want to pass with post the employee info with department id to create the employee
Your BindingResult parameter needs to go directly after your Employee parameter.
Related
I am new to spring boot, can someone help please!!
I have a controller that displays the settings page.
#GetMapping("/setting")
public String settings(Model model){
List<User> user = userDao.findAll();
model.addAttribute("user", user);
return "settings";
}
My query
#Query(value = "SELECT * FROM users u left join user_role ur on u.id = ur.user_id",nativeQuery=true)
List<User> findAll();
On render, the setting page looks like this.
I need to display user role like (Admin/Moderator etc) along with role ids
The mapping of user with role is many to many.
#ManyToMany(cascade=CascadeType.MERGE)
#JoinTable(
name="user_role",
joinColumns={#JoinColumn(name="USER_ID", referencedColumnName="ID")},
inverseJoinColumns={#JoinColumn(name="ROLE_ID", referencedColumnName="ID")})
private List<Role> roles;
In the setting page i am not able to get the value of role.
<tbody>
<tr th:each="u,iterator : ${user}">
<!-- <td th:text="${u.id}"></td> -->
<td th:text="${iterator.index+1}"></td>
<td th:text="${u.name}"></td>
<td th:if="${u.isActive}"><span class="status text-success">•</span> Active</td>
<td th:unless="${u.isActive}"><span class="status text-warning">•</span> InActive</td>
<td>****need to get role here***</td>
</tr>
</tbody>
I would do something like this:
<td><span th:each="role : ${u.roles}" th:text="${role.name}+' '"></span></td>
According in the Role class you have a name field.
The space at the end is just a separator in case you have multiple roles.
Return List of objects
#RequestMapping("/mvt")
public String showMvt(Model model){
model.addAttribute("counts", mouvementRepository.findAll());
return"mvt_";
}
Update one line controller
#RequestMapping(value="/updateMvt/{idmvt}",method = {RequestMethod.GET})
public String updateMvt(#PathVariable(value = "idmvt") int idcpn, #Valid #ModelAttribute("mvt") Mouvement mvt,BindingResult result) {
mouvementRepository.save(mvt);
return "redirect:/mvt";
}
I tried To edit lanes inside tr th:each like this
<tr th:each="count:${counts}">
<form action="#" th:action="#{/updateMvt/{idmvt}(idmvt=${count.idmvt})}" th:object="${count}" method="put">
<table border="0" cellpadding="10">
<tr>
<td>etat</td>
<td>
<select class="select-css" th:field="*{count.etat}">
<option th:value="Enregistrement">Enregistrement</option>
<option th:value="Embarquement">Embarquement</option>
<option th:value="Decollé">Decollé</option>
<option th:value="Annulé" selected>Annulé</option>
<option th:value="null" selected>Aucun</option>
</select>
</td>
</tr>
</table>
</form>
I'm new to spring,i know this solution looks bad,but i'm trying to do my best.
so I tried to do it this way, but I get the error :
Neither BindingResult nor plain target object for bean name 'count'
available as request attribute
Update --------------------------------------------------------------------
so far I managed to create a wrapper class Like this
public class mvtForm {
private int version;
private List<Mouvement> mouvements;//Getters and setters are included
And in my controller I set the movements attribute like this :
#ModelAttribute("wrapper")
#RequestMapping(value = "/mvtall")
public String processQuery(#ModelAttribute mvtForm wrapper, Model model) {
wrapper.setMouvements(mouvementRepository.findAll());
model.addAttribute("wrapper",wrapper);
return "mvt_all";
}
Now I got the view that I needed,
but Is there a way to submit PUT to each lane using JpaRepository ?
th:object must reference an object from Model, not from iteration. So you need to pass count object to model in controller before loading the page, like for example by defining this method in your controller:
#ModelAttribute("updateCount")
public Count count() {
return new Count();
}
class Count should have a field int version that will be unique for each Count object, this is important for updating. Don't forget getters, setters and default constructor - this is important for Thymeleaf.
#ModelAttribute("listOfCounts")
public List<Count> listOfCounts() {
return listOfCounts; //has to be predefined somewhere in class
//as it will be reused throughout application.
}
When you iterate you will be iterating over a listOfCounts. However when updating and pressing update button you will be binding the updateCount object. Make sure to have a hidden field with version in thymeleaf. With this when receiving the update request in your controller, you will receive the updateCount object with the correct version, you can find the correct Count object from the listOfCounts via version and update it.
This is what I'm trying to do:
I have a with a table where I present model attribute which is a list of objects. I present them in table rows using "th:each"
With every row, I present a checkbox, intending to mark some of the presented table rows
I want to submit the form and POST only the list of selected model attributes (only those in the selected table rows)
This is how I present the model attribute list of objects inside table rows (I skipped irrelevant parts of the code):
<form class="form-horizontal"
th:action="#{'/supplier/define'}"
th:object="${foundSuppliers}" th:method="POST">
.....
<tr th:each="supplier, iterStat : ${foundSuppliers.suppliersDTO}">
<td class="hide" th:text="${supplier.id}">ID</td>
<td th:text="${supplier.name}">Name</td>
<td><input th:id="'chk_' + ${supplier.id}"
type="checkbox" th:field="*{foundSuppliers.suppliersDTO}" th:value="${supplier}">
</td>
</tr>
When I submit this form, my "foundSuppliers.suppliersDTO" list is empty even though I check at least one row in my table.
My controller method behind specified th:action (of "form" tag) is:
public String defineSuppliers(#ModelAttribute SupplierListDTO foundSuppliers, Model model) {
...
}
What should I do to actually populate foundSuppliers.suppliersDTO with a list of objects that I marked with checkbox?
To clarify, "foundSuppliers" is a model attribute I pass from controller, and it contains a list of suppliers. The class that I pass as "foundSuppliers" looks like this:
public class SupplierListDTO {
private List<SupplierDTO> suppliersDTO;
.....
}
And I use the same one as th:object inside "form" tag, this is the list I want to pass to backend controller when form is submitted, except the list should contain only the objects inside table rows where I ticked the checkbox.
First, make sure your entire table is enclosed in the same form (mind you, none of this code has been tested):
<form action="/....." method="POST">
<tr th:each="supplier : ${foundSuppliers}">
<td class="hide" th:text="${supplier.id}">ID</td>
<td th:text="${supplier.name}">Name</td>
<td><input th:id="'chk_' + ${supplier.id}" type="checkbox"></td>
</tr>
</form>
Then, on the controller side, you need a custom data binder converting your list of IDs to your domain objects.
#Component
public class IdToSupplierConverterFactory
implements ConverterFactory<String, Supplier> {
private static class IdToSupplierConverter<Supplier>
implements Converter<String, Supplier> {
#PersistenceContext
private EntityManager em;
public Supplier convert(String id) {
return em.findById(id, Supplier.class);
}
}
#Override
public <Supplier> Converter<String, Supplier> getConverter(
Class<Supplier> targetType) {
return new IdToSupplierConverter();
}
}
Spring should do the rest and map your paramaters to:
#PostMapping("/......")
public YourType myControllerMethod(#RequestParam List<Supplier> suppliers) {
return ...;
}
You can do that either through javascript or Spring Boot. Maybe the easiest way is to to give the your checkbox field a name and then retrieve it through your controller. This way, you can easily check if the value of that name/checkbox is null or not. You should come up with something like this:
#RequestMapping(value = "/supplier" , method = RequestMethod. POST)
public void getSuppliers(#RequestParam(value = "nameOfCheckBoxInThymeleaf", required = false) String checkboxValue)
{
if(checkboxValue != null)
{
// do some logic here - get a list of selected suppliers for example
}
else
{
// do some logic here
}
}
I'm trying to use a validation group in Spring, but it doesn't seem to want to work.
When using #Valid User member, it works fine. When I used #Validated(FormValidationGroup.class), it doesn't. This is the method signature.
Code:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String doRegister(Model model, #Valid User member, BindingResult result) {
logger.info("Showing Registration Page....");
if (result.hasErrors()) {
return "createmembers";
}
if (userService.exists(member.getUsername())) {
result.rejectValue("username", "Duplicate Key",
"This email address has already been used");
return "createmembers";
}
else {
userService.create(member);
return "registerSuccess";
}
}
Other method
Code:
#RequestMapping("/createmembers")
public String createMembers(Model model) {
logger.info("Showing Create Members Page....");
model.addAttribute("member", new User());
return "createmembers";
}
The part I've highlighted is all that changes.
The relevant error from the trace seems to be
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'member' available as request attribute
The JSP page is as follows
Code:
<sf:form id="details" method="post" action="${pageContext.request.contextPath}/register" commandName="member">
<table class="formtable">
<tr><td>Name</td><td><sf:input name = "name" path="name" type="text"/><br/><sf:errors path="name" cssClass="error"></sf:errors></td></tr>
<tr><td>Password</td><td><sf:input id="password" name = "password" path="password" type="password"/><br/><sf:errors path="password" cssClass="error"></sf:errors></td></tr>
<tr><td>Confirm Password</td><td><input id = "con_password" name = "con_password" type="password"/><div id="matchpass"></div></td></tr>
<tr><td>Email</td><td><sf:input name = "username" path="username" type="text"/><br/><sf:errors path="username" cssClass="error"></sf:errors></td></tr>
<tr><td>Gender</td><td><sf:select name="gender" path="gender" class="select"><option value = "M">Male</option><option value = "F">Female</option></sf:select></td></tr>
<tr><td>Membership Type</td><td><sf:select name="member_type" path="member_type"><option value = "Senior">Senior</option><option value = "Junior">Junior</option><option value = "Student">Student</option></sf:select></td></tr>
<tr><td>Grade</td><td><sf:select name="grade" path="grade"><option value = "Graded">Graded</option><option value = "Intermediate">Intermediate</option><option value = "Beginner">Beginner</option></sf:select></td></tr>
<tr><td>Address Line 1</td><td><sf:input name = "ad_line1" path="ad_line1" type="text"/><br/><sf:errors path="ad_line1" cssClass="error"></sf:errors></td></tr>
<tr><td>Address Line 2</td><td><sf:input name = "ad_line2" path="ad_line2" type="text"/><br/><sf:errors path="ad_line2" cssClass="error"></sf:errors></td></tr>
<tr><td>City/Town</td><td><sf:input name = "ad_city" path="ad_city" type="text"/><br/><sf:errors path="ad_city" cssClass="error"></sf:errors></td></tr>
<tr><td>County</td><td><sf:input name = "ad_county" path="ad_county" type="text"/><br/><sf:errors path="ad_county" cssClass="error"></sf:errors></td></tr>
<tr><td>Contact Number</td><td><sf:input name = "contact_num" path="contact_num" type="text"/><br/><sf:errors path="contact_num" cssClass="error"></sf:errors></td></tr>
<tr><td>Emergency Contact Name</td><td><sf:input name = "em_con_name" path="em_con_name" type="text"/><br/><sf:errors path="em_con_name" cssClass="error"></sf:errors></td></tr>
<tr><td>Emergency Contact Number</td><td><sf:input name = "em_con_num" path="em_con_num" type="text"/><br/><sf:errors path="em_con_num" cssClass="error"></sf:errors></td></tr>
<tr><td><input value="Register" type="submit"/></td></tr>
</table>
</sf:form>
It's only a partial page as I'm using Apache Tiles, and I've left out the script for checking the password.
As I said, this works fine with the #Valid annotation, but since I'm switching from jdbc to hibernate, I'm losing validation. I want the password field to be between 5-15 for users, but since I am encrypting them, Hibernate won't let them pass validation when writing them to the database.
My understanding in the user clicks on Register, this maps to the createmembers.jsp (which is actually Apache tiles using header.jsp, footer.jsp and createmembers.jsp) - this jsp contains a form which connects to the register mapping in my controller and adds the user object to the model. The register method then reads that objects, does validation and if it's all good, writes to database. If bad, it goes back to the createmembers page, otherwise registerSuccess page. Like I said, I did have Validation working with the#Valid annotation and with JDBC, but with both Spring and Hibernate validating, I need to fix it up a bit.
Fixed it. I had to explicitly annotate the user as a model attribute. Here's the new method signature.
public String doRegister(Model model, #Validated(FormValidationGroup.class) #ModelAttribute("member") User member, BindingResult result)
I have the following requirement. I submit a Model object to a view as follows...
#RequestMapping(value ="/addItem", method = RequestMethod.GET)
public ModelAndView showContacts() {
ModelAndView modelAndView = new ModelAndView("addItem", "command", new Item());
return modelAndView;
}
But on post, I need to retrieve a value apart from the "Item" object (model) that is returned to me. I can't have this variable be a part of the Item model object because it does not belong there. But I need it returned in order to act on that value. How can I get about doing this ?
I.e. In my JSP file, I have the following fields...
<form:input type="text" path="val1"/>
<form:input type="text" path="val2"/>
<form:input type="text" path="val3"/>
Out of the above, only fields val1 and val2 have mappings to the Item object, where as val3 does not. Nevertheless, I need the value of val3 passed back to my controller as well. The code I have right now to handle the POST is as follows, but I can't figure out how to get the value for val3. The code does not compile right now because it says that there is no field or appropriate getter method in the Item class for val3.
#RequestMapping(value = "/postItem", method = RequestMethod.POST)
public String postItem(#ModelAttribute("item") Item item , BindingResult result) {
logger.info("Post Item:");
return "home";
}
How can I modify the above code to suite my requirement ?
Some guidance on this matter will be highly appreciated.
You can pass a map as the model, and include all sorts of different things in there. You are not limited to a single domain object, that constructor is there as a convenience, it is not the only way to do it. There is a variation of the constructor:
public ModelAndView(Object view,
Map model)
Create a new ModelAndView given a View object and a model.
Parameters:
view - View object to render (usually a Servlet MVC View object)
model - Map of model names (Strings) to model objects (Objects).
Model entries may not be null, but the model Map may be null if
there is no model data.