how to update an existed data using spingboot and thymeleaf? - spring-boot

Using Kotlin.
I'm trying to update a User object by:
send old user to update page;
#GetMapping("/update/{id}")
fun updateUser(#PathVariable(value = "id") id: Int, model: Model): String {
val user = userService.findUserByUid(id)
model.addAttribute("user", user)
if (user.uid != 1)
model.addAttribute("allRoles", userService.addUserRole())
else
model.addAttribute("allRoles", userService.adminRole())
return "updateUser"
}
change some vars of that user in html page;
<form action="#" th:action="#{/userManagement/update}" th:object="${user}" method="POST">
<label>昵称</label>
<input type ="text" th:field = "*{usernickname}" placeholder="usernickname" class="form-control mb-4 col-4">
<br>
<label>密码</label>
<input type ="password" th:field = "*{password}" placeholder="password" class="form-control mb-4 col-4">
<div>
<label>职位:
<input type="radio" name="roles"
th:each="myRole : ${allRoles}"
th:text="${myRole.name()}"
th:value="${myRole}"
th:field="*{usertype}"
th:attr ="checked=${myRole.ordinal()==0?true:false}"
/>
</label>
</div>
<br>
<button type="submit" class="btn btn-update">更新员工</button>
</form>
update user data.
#PostMapping(path = ["/update"])
fun updateEmployee(#ModelAttribute("user") user: User, model: Model): String {
try {
user.password = passwordConfig.passwordEncoder().encode(user.password)
userService.updateUser(user)
} catch (ex: RuntimeException) {
model.addAttribute("error", ex.message)
if (user.uid != 1)
model.addAttribute("allRoles", userService.addUserRole())
else
model.addAttribute("allRoles", userService.adminRole())
return "updateUser"
}
return "redirect:/userManagement/"
}
The problem is, at phase 3, the user object i recieved have only usernickname, password and role, other vars becomes null.
For example, at phase 1, the user object is like{uid=5,username=aaa,usernickname=bbb,password=****,usertype=MANAGER,usergroup=DEFAULT,bugList={}}
and when i changed nickname and password at updateUser page, then push that commit btn, the user object at phase 3 will be{uid=0,username=null,usernickname=ccc,password=*****,usertype=MANAGER,usergroup=null,bugList=null}
it seems like phase 1 didnot run correctly, the user object i want to transmit didnot transmited.
I think it is caused by wrong syntax, but i cannot find how to solve it.
update:
User entity:
#Entity
class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
var uid = 0
lateinit var password: String
lateinit var username: String
lateinit var usernickname: String
lateinit var usertype: UserRole
#ManyToOne(fetch= FetchType.EAGER, optional = true)
#JoinColumn(name="groupid")
lateinit var usergroup: UserGroup
#OneToMany(mappedBy = "bid")
lateinit var bugList: List<Bug>
constructor(
password: String,
username: String,
usernickname: String,
usertype: UserRole,
usergroup: UserGroup
) {
this.password = password
this.username = username
this.usernickname = usernickname
this.usertype = usertype
this.usergroup = usergroup
}
constructor()
}
UserRole:
enum class UserRole {
ADMIN, PROGRAMMER, TESTER, MANAGER;
val roleAuthority: GrantedAuthority
get() = SimpleGrantedAuthority("ROLE_$name")
}

Related

Inserting data into related table with thymeleaf

I have table user and table wallet, table wallet have userId so they are connected.
I created controller like this:
#PostMapping("/user/{user_id}/wallets")
public ResponseEntity<?> createWallet(#PathVariable(value = "user_id") Long user_id,
#RequestBody Wallet walletRequest) {
if (walletRepository.existsByUserIdAndWalletName(user_id, walletRequest.getWalletName())) {
return ResponseEntity.badRequest().body(new MessageResponse("You already have wallet with that name, choose another!"));
}
Wallet comment = userRepository.findById(user_id).map(tutorial -> {
walletRequest.setUser(tutorial);
return walletRepository.save(walletRequest);
}).orElseThrow(() -> new IllegalArgumentException("Not found user with id = " + user_id));
return new ResponseEntity<>(comment, HttpStatus.CREATED);
}
And that works fine when I go in postman and hit API /api/user/1/wallets with the appropriate JSON body, I mean wallet is added to user with ID 1.
But I dont know how to transform this to consume in Thymeleaf?
This is all stuff that is related to this thing:
First of all API to show new wallet form:
#GetMapping("/showNewWalletForm")
public String showNewWalletForm(Model model) {
Wallet wallet = new Wallet();
model.addAttribute("wallet", wallet);
return "new_wallet";
}
Form inside html:
<form action="#" th:action="#{/api/wallet/saveWallet}" th:object="${wallet}" method="POST">
<input type="text" th:field="*{walletName}" placeholder="Wallet name" class="form-control mb-4 col-4">
<input type="text" th:field="*{initialBalance}" placeholder="Enter balance" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2"> Save Wallet</button>
</form>
And API to save wallet:
#PostMapping("/saveWallet")
public String saveWallet(#ModelAttribute("wallet") Wallet wallet) {
// save employee to database
walletService.saveWallet(wallet);
return "redirect:/";
}
Obviously I'm getting Column 'user_id' cannot be null since I didnt set it anywhere as I did in postman.
This is Wallet class:
#Entity
#Table(name = "wallet")
public class Wallet {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotEmpty(message = "Please, insert a wallet name")
private String walletName;
private double initialBalance;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "user_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private User user;
To make this work, you need to be able to fetch the logged-in user and since this is something you will need often, I suggest that you create a Spring managed class.
#Component("CurrentUserUtility")
public class CurrentUserUtility {
public static UserDetailsImpl getCurrentUser() {
Authentication tAuthentication = getAuthentication();
if (tAuthentication != null) {
return (UserDetailsImpl) getAuthentication().getPrincipal();
} else {
return null;
}
}
private static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
}
UserDetailsImpl is the class implementing the UserDetails interface and this class should have a userId field (or any other field such as username or email that can be used to uniquely identify the current user).
Now, the only thing you need to do in you controller before saving a new wallet is retrieve the current user using the above utility class.
#PostMapping("/saveWallet")
public String saveWallet(#ModelAttribute("wallet") Wallet wallet) {
//user_id shoudn't be null after the next line
wallet.setUser(userRepository.findById( CurrentUserUtility.getCurrentUser().getUserId() ));
walletService.saveWallet(wallet);
return "redirect:/";
}

Get HttpServletRequest from another server and set cookie into httpServletResponse and send back origin server was request come

I am using spring boot to build example SSO include guest Server at 8280 and authenticate server at 8080 , when access 8280, user will be redirect to server 8080 , login to authority. Now i want get all info of HttpServletRequest, and set cookie for guest server by httpServletResponse. How to i make it ?
I am using spring boot in both server
Here is my code
Configuration Filter Bean at 8280
#Configuration
public class FilterBeanRegistrationConfig {
#Value("${services.auth}")
private String authService;
#Bean
public FilterRegistrationBean <JwtFilter> jwtFilter() {
final FilterRegistrationBean<JwtFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new JwtFilter());
registrationBean.setInitParameters(Collections.singletonMap("services.auth", authService));
registrationBean.addUrlPatterns("/protected-resource");
return registrationBean;
}
} // END
application.propertie at 8280
services.auth=http://localhost:8080/login
server.port=8280
AuthenticatedUser.java
public class AuthenticatedUser {
private String email;
private String username;
private String password;
private String resourcesUrl;
private String token;
public AuthenticatedUser(){
}
public AuthenticatedUser(String email, String username, String password, String resourcesUrl, String token) {
this.email = email;
this.username = username;
this.password = password;
this.resourcesUrl = resourcesUrl;
this.token = token;
}
// getter and setter
} // end class
Controller at 8080
#Controller
public class LoginControllerFromVue {
private static final String jwtTokenCookieName = "JWT-TOKEN";
private static final String signingKey = "signingKey";
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Autowired
private UserService userService;
#RequestMapping("/")
public String home(){
return "redirect:/login";
}
#RequestMapping("/login")
public RedirectView method(HttpServletResponse httpServletResponse , HttpServletRequest httpServletRequest){
RedirectView redirectView = new RedirectView("http://localhost:4000/login?");
redirectView.setPropagateQueryParams(true);
return redirectView;
}
#PostMapping("/api/login")
public String loginUser(#RequestBody AuthenticatedUser theUser , HttpServletResponse httpServletResponse) {
if (theUser == null || userService.findUserByUsername(theUser.getUsername()) == null) {
return null;
}
if (! passwordEncoder.matches(theUser.getPassword(),userService.findUserByUsername(theUser.getUsername()).getPassword())) {
return null;
}
String token = JwtUtil.generateToken(signingKey, theUser.getUsername());
CookieUtil.create(httpServletResponse, jwtTokenCookieName, token, false, -1, httpServletRequest.getServerName());
return "redirect:"+theUser.getResourcesUrl();
}
}
Config Axios in Vuejs
import axios from "axios";
export default axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-type": "application/json",
}
});
Login.vue
<template>
<div class="submitform">
<form class="form" #submit.prevent="loginUser">
<div v-if="!submitted" >
<div class="form-group">
<label for="name">Username</label>
<input type="text" class="form-control" id="username" required v-model="user.username" name="username">
</div>
<div class="form-group">
<label for="age">Password</label>
<input type="password" class="form-control" id="password" required v-model="user.password" name="password">
</div>
<div id="error">
<span v-if="error">Username or Password invalid</span>
</div>
<hr>
<button type="submit" class="btn btn-success">Submit</button>
</div>
</form>
<hr>
<button v-on:click="getPathResources" class="btn btn-warning">Get Resources</button>
|
<button v-on:click="authorisedRedirect" class="btn btn-warning">Appcept Redirect</button>
</div>
</template>
<script>
import http from "../http-common";
export default {
name: "login-User",
data() {
return {
user: {
id: 0,
email : "",
username: "",
password: "",
// resourcesUrl:location.host
resourcesUrl : this.$route.query.redirect
},
error: false,
submitted: false
};
},
methods: {
loginUser() {
var data = {
username: this.user.username,
password: this.user.password,
// resourcesUrl:location.host
resourcesUrl : this.$route.query.redirect
};
http
.post("/login", data)
.then(model => {
// this.user.id = response.data.id;
console.log(model.data);
if (model.data !== "") {
this.$router.push('/authorised');
this.submitted = true;
} else {
this.submitted = false;
this.user.username = "";
this.user.password = "";
this.error = true;
}
})
.catch(e => {
console.log(e);
});
},
getPathResources(){
// var currentServername = location.hostname;
var currentHost = location.host;
var currentUrl = location.pathname;
console.log(currentHost + currentUrl);
console.log(this.$route.query.redirect);
},
authorisedRedirect(){
window.open("http://localhost:8280/protected-resource", "_blank");
}
}
};
</script>
<style>
.submitform {
max-width: 300px;
margin: auto;
}
.form {
background-color: rgb(245, 245, 245)
}
#error {
background-color: beige;
border-radius: 3px;
}
</style>
When I log in with a valid account, I still cannot transfer to 8280 and still remain in the login page, it seems that setting the cookie to the 8280 server has not been successfully implemented by httpservletResponse. how to i setup it or any other solution to it work , if anyone know where's this problem please tell he how to sovle it and i appreciate!!!

Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection in Spring Boot, JSP

I have this problem in my code, where I cannot submit a signup form in jsp. Here are the code intervening in the signup operation.
User.java
#Entity
#Table(name = "user", catalog = "spring_abc", uniqueConstraints = {#UniqueConstraint(columnNames = "email"),
#UniqueConstraint(columnNames = "username")})
public class User implements java.io.Serializable {
public static final String ROLE_ADMIN = "admin";
public static final String ROLE_MEMBER = "member";
private static final long serialVersionUID = 7376961072110620611L;
private Integer id;
private Long commentCount;
private Date createAt;
private String description;
#Email(message = "Entrez le format de l'email correct")
private String email;
private long number;
private String password;
public void setDepartement(String departement) {
this.departement = departement;
}
private long points;
private String role;
#Size(max = 60, message = "Pas plus de soixante caractères")
private String signature;
private Long topicCount;
#Size(max = 60, message = "Pas plus de soixante caractères")
private String twitter;
private Date updateAt;
#Pattern(regexp = "^(?!_)(?!.*?_$)[A-Za-z0-9|_]{3,9}", message = "Nom d'utilisateur, ne peut pas commencer ou se terminer par un trait de soulignement")
private String username;
private Set<Follow> followsForFollowerId = new HashSet<Follow>(0);
private Set<Notification> notifications = new HashSet<Notification>(0);
private Set<Topic> topics = new HashSet<Topic>(0);
private Set<Comment> comments = new HashSet<Comment>(0);
private Set<Focus> focuses = new HashSet<Focus>(0);
private Set<Collection> collections = new HashSet<Collection>(0);
private Set<Follow> followsForFollowingId = new HashSet<Follow>(0);
private Set<Comment> likeComments = new HashSet<Comment>();
The methode signup the service Part.
#Transactional
public User signup(User user, String password1, Errors errors) {
if (errors.hasErrors()) {
return null;
}
String username = user.getUsername();
String password = user.getPassword();
String email = user.getEmail();
if (userRepo.findOneByUsername(username) != null) {
errors.rejectValue("username", "username", "Nom d'utilisateur déjà enregistré");
} else if (userRepo.findOneByEmail(email) != null) {
errors.rejectValue("email", "email", "E-mail est déjà enregistré");
} else if (!password.equals(password1)) {
errors.rejectValue("password", "password", "Les mots de passe ne se correspondent pas");
}
if (errors.hasErrors()) {
return null;
}
user.setPassword(EncryptUtil.encryptUsernameAndPassword(username, password));
user.setCreateAt(new Date());
return userRepo.save(user);
}
Controller Account.java
#RequestMapping(value = "/signup", method = RequestMethod.POST)
public String singupAction(#Validated User user,
Errors erros,
String password1,
RedirectAttributes attributese,
HttpServletRequest request) {
User signinUser = userServ.signup(user, password1, erros);
if (erros.hasErrors()) {
attributese.addFlashAttribute("user", user);
attributese.addFlashAttribute("error", erros.getAllErrors());
return "redirect:/account/signup";
}
request.getSession().setAttribute("user", signinUser);
attributese.addFlashAttribute("msg", "Vous êtes inscrit avec succès");
return "redirect:/";
}
Signup.jsp, The problem appears when i try to validate information.
<form action="${x}/account/signup" data-toggle="validator" role="form" method="POST">
<input class="form-control" data-error="S'il vous plaît entrer une adresse email valide" placeholder="E-mail" type="email" id="email" name="email" value="${user.email}" />
<input class="form-control" id="username" data-error="Entre 6 et 18 caractères" pattern="^[_A-z0-9]{6,18}$" placeholder="Votre username" type="text" name="username" value="${user.username}" />
<input class="form-control" data-minlength="6" type="password" name="password" id="password" placeholder="Mot de passe" data-error="Entre 6 et 18 caractères" />
<input type="submit" class="btn btn-info btn-block" value="S'inscrire">
The stack I'm getting doesn't make any sense to me. It doesn't point out the problem
org.apache.jasper.JasperException: javax.el.ELException: java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:492)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:378)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:501)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
Caused by: javax.el.ELException: java.lang.IllegalAccessException: Class javax.el.BeanELResolver can not access a member of class java.util.Collections$UnmodifiableCollection with modifiers "public"
at javax.el.BeanELResolver.invokeMethod(BeanELResolver.java:742)
at javax.el.BeanELResolver.invoke(BeanELResolver.java:470)
at javax.el.CompositeELResolver.invoke(CompositeELResolver.java:257)
You need to add getters and setters in your entity for each field.
e.g. private long number;
Should have defined following in your entity.
public long getNumber(){ return this.number;}
public void setNumber(long number){ this.number = number; }
from your stacktrace it is clear that it is trying to access fields with public getter method but it couldn't find it so thrown exception.

how do I pass the selected parameters in the checkbox from one jsp page to another jsp page?

I have to make the switch to selected values ​​within some checkboxes in a jsp page but after the selection and after pressing the "Send" button, I generate this error with the following description: HTTP Status 400: The request sent by the client was syntactically incorrect.
Where am I wrong?
TaskController.java
#RequestMapping(value="/newTask", method = RequestMethod.GET)
public String task(#ModelAttribute Task task, Model model) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String s = auth.getName();
Student student = studentFacade.retrieveUser(s);
List<Job> jobs = new ArrayList<>();
if(!(auth instanceof AnonymousAuthenticationToken)) {
jobs = facadeJob.retriveAlljobs();
model.addAttribute("job", getMathRandomList(jobs));
model.addAttribute("image", imageFacade.retriveAllImages());
List<Image> img = imageFacade.retriveAllImages();
task.setImages(img);
task.setStudent(student);
taskFacade.addTask(task);
List<Long> images = new ArrayList<>();
for(Image i : img)
images.add(i.getId());
model.addAttribute("images", images);
}
return "users/newTask";
}
#RequestMapping(value="/taskRecap", method = RequestMethod.POST)
public String taskRecap(#ModelAttribute Task task, Model model,BindingResult result) {
model.addAttribute("task", task);
return "users/taskRecap";
}
newTask.jsp
<form:form method="post" action="taskRecap" modelAttribute="task" name="form">
<form:checkboxes path="images" items="${images}" value="yes" />
<td><input type="submit" value="Send" /></td>
</form:form>
taskRecap.jsp Immages
<c:forEach var="image" items="${task.images}">
<c:out value="${image.id}" />
</c:forEach>
Task.java
#Entity
public class Task {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private Student student;
#ManyToMany
List<Image> images;
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public Task() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Task(Long id, Student student, List<Image> images) {
super();
this.id = id;
this.student = student;
this.images = images;
}
public List<Image> getImages() {
return images;
}
public void setImages(List<Image> images) {
this.images = images;
}
}
Using Query parameter
<a href="edit.jsp?Name=${user.name}" />
Using Hidden variable .
<form method="post" action="update.jsp">
<input type="hidden" name="Name" value="${user.id}">
if you use either of the first 2 methods you can access your value like this:
String userid = session.getParameter("Name");
you can send Using Session object.
session.setAttribute("Name", UserName);
These values will now be available from any jsp as long as your session is still active.
if you use the third option you can access your value like this:
String userid = session.getAttribute("Name");

Spring MVC Pre Populate Checkboxes

First little background info. Got a fairly standard User Role relationship where the User can have many roles. I have roles defined as a set within the user class. Now I know that html forms have all the values as strings and trying to get values as my custom Role object does not work. I implemented an initbinder to convert the id's back into object so that I can retrieve the selected values off of my checkboxes, that part works.
But I can't seem to go back the other way. I retrieve a User from the database that already has roles and want to pre populate role checkboxes with all the roles that a user has. Based on this example :
Checkboxes example
They say that:
form:checkboxes items="${dynamic-list}" path="property-to-store"
For multiple checkboxes, as long as the “path” or “property” value is
equal to any of the “checkbox values – ${dynamic-list}“, the matched
checkbox will be checked automatically.
My interpretation of that is I should be able to feed it a Set of all the roles and define the path to be the roles from the User object and it should match them thus causing the check box to pre populate.
Every example out there seems to have the value of dynamic-list as a String[]. Well thats great and dandy but how does this work for custom objects that our defined as a Set? Can I still use this one line definition for checkboxes or do I need to do some kind of data binding heading into the view also?
Here is my user dto, user controller, custom form binder, and user edit page.
User DTO
#Entity
#Table
public class User extends BaseDto
{
#Column(updatable = false) #NotBlank
private String username;
#Column(name = "encrypted_password") #Size(min = 6, message = "password must be at least 6 characters") #Pattern(regexp = "^\\S*$", message = "invalid character detected")
private String password;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column #NotNull
private boolean enabled;
#Column #Email #NotBlank
private String email;
#Transient
private String confirmPassword;
#ManyToMany(targetEntity = Role.class, fetch = FetchType.EAGER, cascade = CascadeType.REFRESH) #JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
public User()
{
}
public User(final String usernameIn, final String passwordIn, final String firstNameIn, final String lastNameIn, final String emailIn, final boolean enabledIn)
{
username = usernameIn;
password = passwordIn;
firstName = firstNameIn;
lastName = lastNameIn;
email = emailIn;
enabled = enabledIn;
}
public String getUsername()
{
return username;
}
public void setUsername(final String usernameIn)
{
username = usernameIn;
}
public String getPassword()
{
return password;
}
public void setPassword(final String passwordIn)
{
password = passwordIn;
}
public String getFirstName()
{
return firstName;
}
public void setFirstName(final String firstNameIn)
{
firstName = firstNameIn;
}
public String getLastName()
{
return lastName;
}
public void setLastName(final String lastNameIn)
{
lastName = lastNameIn;
}
public String getEmail()
{
return email;
}
public void setEmail(final String emailIn)
{
email = emailIn;
}
public String getConfirmPassword()
{
return confirmPassword;
}
public void setConfirmPassword(final String confirmPasswordIn)
{
confirmPassword = confirmPasswordIn;
}
public boolean isEnabled()
{
return enabled;
}
public void setEnabled(final boolean enabledIn)
{
enabled = enabledIn;
}
public Set<Role> getRoles()
{
return roles;
}
public void setRoles(final Set<Role> rolesIn)
{
roles = rolesIn;
}
}
User Controller
#Controller #RequestMapping("/user")
public class UserController
{
#Autowired private UserService userService;
#Autowired private UserDao userDao;
#Autowired private RoleDao roleDao;
#InitBinder
public void bindForm(final WebDataBinder binder)
{
binder.registerCustomEditor(Set.class, "roles", new CustomFormBinder<RoleDao>(roleDao, Set.class));
}
#RequestMapping(method = RequestMethod.GET)
public String index(final ModelMap modelMap)
{
return "/user/index";
}
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String create(final ModelMap modelMap)
{
modelMap.addAttribute("userInstance", new User());
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/create";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String save(final ModelMap modelMap, #Valid #ModelAttribute("userInstance") final User user, final BindingResult bindingResult)
{
// TODO move to service validation
if (user.getPassword() == null || !user.getPassword().equals(user.getConfirmPassword()) )
{
bindingResult.addError(new FieldError("userInstance", "password", "password fields must match"));
bindingResult.addError(new FieldError("userInstance", "confirmPassword", "password fields must match"));
}
if (user.getRoles() == null || user.getRoles().isEmpty())
{
bindingResult.addError(new FieldError("userInstance", "roles", "Must select at least one role for a User"));
}
if (bindingResult.hasErrors())
{
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/create";
}
userService.save(user);
return "redirect:/user/list";
}
#RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
public String edit(#PathVariable final Integer id, final ModelMap modelMap)
{
final User user = userDao.find(id);
if (user != null)
{
modelMap.addAttribute("userInstance", user);
modelMap.addAttribute("validRoles", new HashSet<Role>(roleDao.findAll()));
return "/user/edit";
}
return "redirect:/user/list";
}
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String editCurrent(final ModelMap modelMap)
{
return edit(userService.getLoggedInUser().getId(), modelMap);
}
#RequestMapping(value = "/update", method = RequestMethod.POST)
public String update(#Valid #ModelAttribute("userInstance") final User user, final BindingResult bindingResult)
{
if (bindingResult.hasErrors())
{
return "/user/edit";
}
userService.save(user);
return "redirect:/user/list";
}
#ModelAttribute("userInstances")
#RequestMapping(value = "/list", method = RequestMethod.GET)
public List<User> list()
{
return userDao.findAll();
}
}
Custom Form Binder
public class CustomFormBinder<T extends GenericDao> extends CustomCollectionEditor
{
private final T dao;
private static final Logger LOG = LoggerFactory.getLogger(CustomFormBinder.class);
public CustomFormBinder(final T daoIn, final Class collectionType)
{
super(collectionType, true);
dao = daoIn;
}
#Override
protected Object convertElement(final Object element)
{
try
{
// forms should return the id as the itemValue
return dao.find(Integer.valueOf(element.toString()));
}
catch (NumberFormatException e)
{
LOG.warn("Unable to convert " + element + " to an integer");
return null;
}
}
}
User Edit View
<html>
<head>
<title>Create User</title>
</head>
<body>
<c:url value="/user/update" var="actionUrl"/>
<form:form method="post" commandName="userInstance" action="${actionUrl}">
<h1>Edit User ${userInstance.username}</h1>
<div>
<form:label path="username">Username:</form:label>
<form:input path="username" id="username" readonly="true"/>
</div>
<div>
<form:label path="password">Password:</form:label>
<form:input path="password" id="password" type="password" readonly="true"/>
<tag:errorlist path="userInstance.password" cssClass="formError"/>
</div>
<div>
<form:label path="firstName">First Name:</form:label>
<form:input path="firstName" id="firstName"/>
<tag:errorlist path="userInstance.firstName" cssClass="formError"/>
</div>
<div>
<form:label path="lastName">Last Name:</form:label>
<form:input path="lastName" id="lastName"/>
<tag:errorlist path="userInstance.lastName" cssClass="formError"/>
</div>
<div>
<form:label path="email">Email:</form:label>
<form:input path="email" id="email" size="30"/>
<tag:errorlist path="userInstance.email" cssClass="formError"/>
</div>
<div>
**<%--Want to Pre Populate these checkboxed--%>
<form:checkboxes title="Assigned Roles:" path="roles" id="roles" items="${validRoles}" itemLabel="displayName" itemValue="id" element="div"/>**
<tag:errorlist path="userInstance.roles" cssClass="formError"/>
</div>
<form:hidden path="enabled"/>
<form:hidden path="id"/>
<form:hidden path="version"/>
<div class="submit">
<input type="submit" value="Update"/>
Cancel
</div>
</form:form>
</body>
</html>
You need a correct implemented equals method for Role!
If this is not enough have a look at class oorg.springframework.web.servlet.tags.form.AbstractCheckedElementTag. The method void renderFromValue(Object item, Object value, TagWriter tagWriter) is where the the checked flag is set.

Resources