Customize items in form select - java

In my registration form, I have a field that give to users the possiblity to choose roles. But, I want to, only, show two roles : USER and MODERATOR.
But, I don't know how to proceed.
this registration form jsp :
<div class="row">
<div class="form-group col-md-12">
<label style="color:#ffffff;" class="col-md-3 control-lable" for="userProfiles">Roles</label>
<div class="col-md-7">
<form:select path="userProfiles" items="${roles}" multiple="true" itemValue="id" itemLabel="type" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userProfiles" class="help-inline"/>
</div>
</div>
</div>
</div>
I have an enum : UserProfileType
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
}
And this is how it look :
This my controller, the part responsible of registration
//new user
#RequestMapping(value = "/registrationForm", method = RequestMethod.GET)
public String newUser(User user, ModelMap model) {
//User user = new User();
model.addAttribute("user", user);
model.addAttribute("loggedinuser", getPrincipal());
return "registrationForm";
}
//save user
#RequestMapping(value = { "/registrationForm" }, method = RequestMethod.POST)
public String saveUser1(#Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registrationForm";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registrationForm";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
//return "success";
return "registrationsuccess";
}
I am using spring mvc/security and hibernate.
Thanks in advance

The data to be displayed by the page should be provided and manipulated by the controller. Filter the roles in your controller before handing over to the view.
Depending on how you are adding attributes to the model you can do it as foLlows (or any equivalent way as Spring MVC is flexible)
You could create methods in your Enum class to return the filtered values according to yours needs:
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
public static List<UserProfileType> getAdminRoles(){
return Arrays.asList(UserProfileType.USER , UserProfileType.MODERATOR);
}
}
#ModelAttribute("roles")
public List<UserProfileType> roles(){
return UserProfileType.getAdminRoles();
}
You can also filter the roles in the view but its not recommended to have control logic in your view
<form:select path="userProfiles"multiple="true" class="form-control input-sm">
<c:forEach items="${roles}" var = "role">
<c:if test="${role.type eq 'USER' or role.type eq 'MODERATOR'}">
<form:option value="${role.id}" label="${role.type}"/>
</c:if>
</c:forEach>
</form:select>

Related

Write value from Select in DTO Thymeleaf

I have an Entity "User". I have an Enum "Usertyp". Users have a field "usertyp". I want to change the "Usertyp" by passing a DTO to my controller. The problem is that the usertype gets changed to Null in the DB
Another minor problem is that I want the default value of the selectfield to have the users current usertype as default value. I tried with "
th:selected="${u.usertyp}">
and also with an if statement. Neither worked.
I am very grateful for any help. I really struggle with Thymeleaf.
Controller:
#PostMapping("editUser/{userId}")
public String editUser(#ModelAttribute("sessionUser") User sessionUser, #Valid #ModelAttribute("userDTO") UserDTO userDTO, #PathVariable Long userId, Model model){
if(sessionUser==null || sessionUser.getUsertyp() == Usertyp.USER)
{
return "redirect:/";
}
else {
User changedUser = userService.findById(userId);
changedUser.setUsertyp(Usertyp.fromString(userDTO.getUsertyp()));
userService.save(changedUser);
return "redirect:/administration";
}
}
DTO
public class UserDTO {
//TODO usertyp anpassem
private String usertyp;
public UserDTO(String usertyp) {
this.usertyp = usertyp;
}
public String getUsertyp() {
return usertyp;
}
public void setUsertyp(String usertyp) {
this.usertyp = usertyp;
}
}
Template
<ul class="list-group list-group-flush">
<span th:each="u : ${userList}">
<li class="list-group-item">
<span th:text="${u.username}"></span>
<form th:object="${userDTO}" th:action="#{/editUser/{userId}(userId=${u.id})}" method="Post" id="Rolle">
<select th:field="*{usertyp}" form="Rolle">
<option
th:each="usertyp : ${T(com.example.myproject.entities.Usertyp).values()}"
th:text="${usertyp.displayText}"
th:value="${usertyp.displayText}">
</option>
</select>
<input class="btn btn-primary" type="submit" value="Speichern">
</form>
</li>
</span>
</ul>
I already changed my DTO field type from "Usertyp" to String
th:selected="${u.usertyp}">
The th:selected property should convert to selected="selected" or just selected in raw html, I think instead you want something like th:selected="${u.usertyp == usertyp}"
You didn't show your #GetMapping setup for the thyme leaf page, so I didn't include a user list, but here's a basic example of what I think you're attempting to do:
User Controller:
#Controller
public class UserController {
#GetMapping("user")
public String getUserTypePage(#ModelAttribute("userDTO") UserDTO userDTO) {
// just setting it to admin so that it will show the default selection of not the first item
userDTO.setUserType(UserType.ADMIN);
return "user";
}
#PostMapping("user")
public void postUserTypePage(#ModelAttribute("userDTO") UserDTO userDTO) {
System.out.println("USER DTO TYPE - " + userDTO.getUserType().getDisplayText());
}
}
UserType enum:
public enum UserType {
USER("Standard User"),
ADMIN("Administrator");
private final String displayText;
UserType(String displayText) {
this.displayText = displayText;
}
public String getDisplayText() {
return displayText;
}
}
UserDTO:
public class UserDTO {
private UserType userType;
public UserDTO(UserType userType) {
this.userType = userType;
}
public UserType getUserType() {
return userType;
}
public void setUserType(UserType userType) {
this.userType = userType;
}
}
Thymeleaf view:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<title>User Type</title>
</head>
<body>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<form th:object="${userDTO}" th:action="#{/user}" method="POST" id="Rolle">
<select th:field="*{userType}" form="Rolle">
<option
th:each="uType : ${T(com.example.demo.models.UserType).values()}"
th:text="${uType.displayText}"
th:value="${uType}"
th:selected="${userType == uType}">
</option>
</select>
<input class="btn btn-primary" type="submit" value="Speichern">
</form>
</li>
</ul>
</body>
</html>
Specifically you want the th:value to be bound to the enum value (if you'd prefer to use an enum rather than a string):
th:value="${uType}"
And then the th:selected set based off of equality of the enum to the UserType option in being looped through:
th:selected="${userType == uType}">
A few additional things to check:
Are you establishing the #ModelAttribute("userDTO") in the GET variant of your controller?
Log out the value of the userType in your post method to confirm it's value before any database operation (to confirm that it is actually coming in as null from the post and not being set to null somewhere in the db operation).
Try just passing along the value for the userType in the form (instead of using a select input item) to confirm that the currentValue for your model is getting fed through i.e.: <input th:field="*{userType}" th:value="${userType}">

Spring Thymeleaf classappend not appending the classes

I'm trying to classappend a few classes dependant on errors found in the validation process of a form. But for some reason, it's not appending the classes. My CSS is correct as it works without using the classappend error check and also my validation is correct as it will detect an error in the form but just won't append the css classes. The specific method used is updateRole() in the RoleController class. Below is all my code:
RoleController.java
#Controller
public class RoleController {
#Autowired
private RoleServiceImpl roleService;
#RequestMapping("/roles")
public String viewAllRoles(ModelMap model) {
List<Role> roles = roleService.findAll();
model.put("roles", roles);
if (!model.containsAttribute("role")) {
model.put("role", new Role());
}
return "roles";
}
#RequestMapping(value = "/roles", method = RequestMethod.POST)
public String addRole(#Valid Role role, BindingResult result, RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
// Add the error message as a flash attribute
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.role", result);
// Add the role object created so the user can see their inital input after redirect
redirectAttributes.addFlashAttribute("role", role);
return "redirect:/roles";
}
roleService.save(role);
redirectAttributes.addFlashAttribute("flash", new FlashMessage("Role successfully added", FlashMessage.Status.SUCCESS));
return "redirect:/roles";
}
#RequestMapping(value = "/roles/{roleId}")
public String viewRole(#PathVariable Long roleId, ModelMap model) {
Role role = roleService.findById(roleId);
model.put("role", role);
return "role";
}
#RequestMapping(value = "/roles/{roleId}", method = RequestMethod.POST)
public String updateRole(#Valid Role role, BindingResult result, RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.role", result);
redirectAttributes.addFlashAttribute("role", role);
return String.format("redirect:/roles/%s/edit", role.getId());
}
roleService.save(role);
redirectAttributes.addFlashAttribute("flash", new FlashMessage("Role successfully updated", FlashMessage.Status.SUCCESS));
return "redirect:/roles";
}
#RequestMapping(value = "/roles/{roleId}/edit")
public String editRole(#PathVariable Long roleId, ModelMap model) {
Role role = roleService.findById(roleId);
model.put("action", String.format("/roles/%s", roleId));
model.put("role", role);
return "role_edit";
}
}
role_edit.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="base :: head('role_edit')"></head>
<body>
<header th:replace="base :: header"></header>
<nav>
<ul>
<li><a th:href="#{projects}">Projects</a></li>
<li><a th:href="#{collaborators}">Collaborators</a></li>
<li class="selected"><a th:href="#{roles}">Roles</a></li>
</ul>
</nav>
<section>
<div class="container wrapper">
<form th:action="#{${action}}" method="post" th:object="${role}">
<input type="hidden" th:field="*{id}">
<div class="edit-input" th:classappend="${#fields.hasErrors('name')}? 'edit-error test' : ''">
<label> Role Name:</label>
<input type="text" th:field="*{name}">
</div>
<div th:class="${#fields.hasErrors('name')}? 'error' : ''">
<div class="testtwo error-message" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
</div>
<div class="actions">
<button class="button" type="submit" value="Submit">Save</button>
<a th:href="#{|/roles/*{id}|}" class="button button-secondary">Cancel</a>
</div>
</form>
</div>
</section>
</body>
</html>
If anyone could help it would be great, as I'm really stuck on this one.

Neither BindingResult nor plain target object for bean name when running application

index.jsp
<f:form action="emp_change.htm" method="POST" commandName="index">
<div id="login_box">
<div id="form_val">
<div class="label">Username:</div>
<div class="control"><f:input path="emailId" /></div>
<div style="clear:both;height:0px;"></div>
<div class="label">Password:</div>
<div class="control"><f:input path="password" type="password" /></div>
<div style="clear:both;height:0px;"></div>
<div id="msgbox"></div>
<div id="login_foot">
<input type="submit" name="action" id="login" value="Login" class="send_button" />
</div>
</div>
</div>
</f:form>
AdminInfoControl.java
#Controller
public class AdminInfoControl {
private AdminInfoService service;
#RequestMapping(value = "/emp_change", method = RequestMethod.POST)
public String doActions(#ModelAttribute JtAdminInfo emp, BindingResult result, #RequestParam String action, Map<String, Object> map) {
service = new AdminInfoService();
JtAdminInfo empResult = new JtAdminInfo();
switch (action.toLowerCase()) {
case "login":
JtAdminInfo search = service.getFindAdmin(emp.getEmailId());
empResult = search != null ? search : new JtAdminInfo();
break;
}
map.put("index", empResult);
map.put("empList", service.getAll());
return "index";
}
}
I'm getting following error :
Neither BindingResult nor plain target object for bean name 'emp_change' available as request attribute
Anyone please help me to correct this. Please let me know, if information is not sufficient.
Just answered on almost the same question.. You are obtaining emp_change as a model attribute in doActions method but you didn't set it as a model attribute previously. So, set your emp_change as a model attribute in some method that e.g. shows your index.jsp page. Something like this:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showIndex() {
ModelAndView mav = new ModelAndView("index");
mav.addObject("emp_change", new JtAdminInfo ());
return mav;
}
I have added following method in my controller and works fine.
#RequestMapping("/index")
public String setupForm(Map<String, Object> map) {
map.put("index", new JtAdminInfo());
return "index";
}

Edit form validation with Spring MVC

I use Spring MVC and Spring form validation in my project.
There is class named Group in object model and I created form for editing it.
Form
<spring:url var="saveGroup" value="/teacher/groups/save"/>
<form:form action="${saveGroup}" method="post" modelAttribute="group">
<form:hidden path="id"/>
<div id="nameDiv" class="control-group">
<form:label path="title">Title:</form:label>
<form:input path="title"/>
<form:errors path="title"/>
</div>
<div id="specDiv" class="control-group">
<form:label path="title">Specialty:</form:label>
<form:select path="specialty">
<form:options items="${specialties}" itemValue="id" itemLabel="title"/>
</form:select>
</div>
<div class="center">
<spring:url var="groups" value="/teacher/groups"/>
<input class="btn btn-primary" type="submit" value="Save"/>
<a class="btn" href="${groups}"> Cancel </a>
</div>
</form:form>
Controller
#Controller
#RequestMapping("/teacher/groups")
public class GroupsController {
#Autowired
private GroupService groupService;
#Autowired
private SpecialtyService specialtyService;
#ModelAttribute("group")
public Group setGroup(Long id) {
if (id != null) {
return groupService.read(id);
} else {
return new Group();
}
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Specialty.class, "specialty",
new SpecialtyEditor(specialtyService));
binder.setValidator(new GroupValidator());
}
#RequestMapping("")
public ModelAndView groups() {
return new ModelAndView("teacher/groups/list", "groups",
groupService.list());
}
#RequestMapping("/edit")
public ModelAndView editGroup() {
return new ModelAndView("teacher/groups/edit", "specialties",
specialtyService.list());
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return "forward:/teacher/groups/edit";
}
groupService.update(group);
return "redirect:/teacher/groups";
}
}
I want to set the adequate behavior of my form in the case of failed validation. I.e. it should save its state but only show validation error message (as when using javascript to validate).
I thought that "forward:/teacher/groups/edit" will again forward request to editGroup() with saved objects group and result. But when I failed validation form just reloads and show start state of edited group: no errors and no saved changes.
How can I do that correctly?
Thanks!
I solved problem by not forwarding request to other method but sending answer to user immediately. Now it works and looks like:
#RequestMapping(value = "/save", method = RequestMethod.POST)
public ModelAndView saveGroup(#Valid Group group, BindingResult result) {
if (result.hasErrors()) {
return new ModelAndView("/teacher/groups/edit", "specialties", specialtyService.list());
}
groupService.update(group);
return new ModelAndView("redirect:/teacher/groups");
}

Syntactically incorrect request sent upon submitting form with invalid data in Spring MVC (which uses hibernate Validator)

Login form:
<f:form class="form-horizontal" method="post" action="/login"
commandName="logindata">
<fieldset>
<legend class="text-info">Login</legend>
<div class="control-group">
<f:label path="uname" class="control-label" for="uname">Username</f:label>
<div class="controls">
<f:input type="text" path="uname" name="uname" id="uname"
placeholder="Username" />
</div>
</div>
<div class="control-group">
<f:label path="pwd" class="control-label" for="pwd">Password</f:label>
<div class="controls">
<f:input type="password" path="pwd" name="pwd" id="pwd"
placeholder="Password" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn" id="login">
Login <i class="icon-chevron-right"></i>
</button>
</div>
</div>
<div id="errormsg" class="alert alert-error">${message}</div>
</fieldset>
</f:form>
the loginData class:
package com.demo.forms;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
public class loginData {
#Length(min=4)
private String uname;
#NotEmpty
private String pwd;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
Controller methods for showing and submitting the form: (Shows homepage which contains signup form and login form)
#RequestMapping(value = "/", method=RequestMethod.GET)
public String showHome(Model model)
{
loginservice.logout();
model.addAttribute("logindata", new loginData());
model.addAttribute("signupdata", new signupData());
return "home";
}
Method called upon submitting login form:
#RequestMapping(value = "login", method=RequestMethod.POST)
public String submitloginForm(#Valid loginData logindata, SessionStatus state, Model model, BindingResult result)
{
if((loginservice.loggedin()) || (result.hasErrors()))
{
return showHome(model);
}
else
{
String uname = logindata.getUname();
String pwd = logindata.getPwd();
if(loginservice.login(uname, pwd))
{
model.addAttribute("user",uname);
return "redirect:profile";
}
else
{
model.addAttribute("message","Invalid Username/Password");
return showHome(model);
}
}
}
The login works fine when the data entered is 'valid' (either correct or wrong). However, when it is invalid, for instance, when the password field is empty or the username is less than four characters long, following error is shown:
The request sent by the client was syntactically incorrect.
Any idea how this might be fixed?
You have to modify the order of your arguments. Put the BindingResult result parameter always directly after the parameter with the #Valid annotation.
#RequestMapping(value = "login", method=RequestMethod.POST)
public String submitloginForm(#Valid loginData logindata, BindingResult result,
SessionStatus state, Model model)
This was even mentioned in this weeks This Week in Spring - March 5th, 2013 blog entry
Someone asked me this the other day and I felt like it was worthy of a
mention: in your Spring MVC #Controller class handler methods, make
sure that the BindingResult argument is immediately after the model or
command argument, like this: #RequestMapping(...) public String
handleRequest( #ModelAttribute #Valid YourCustomPojo attempt,
BindingResult result). In this example, handleRequest will validate
the POJO (YourCustomPojo) - checking the POJO for JSR303-annotations
and attempting to apply the constraints because the POJO is annotated
with #Valid - and stash any errors in the BindingResult, which it
makes available if we ask for it.
Spring will
0) determin the handler method
1) create an instance of loginData
2) populate it
3) validate it, and store the validation result in BindingResult
4) invoke the method (with loginData and BindingResult values), no matter whenever the binding Result contains an error or not

Categories