Spring Validator validate method never called - java

I have two close to each other controllers - one for products and one for users.
I'd like to add Spring Validation to both controllers.
So I added ProductValidator and UserValidator classes which implement Validator.
ProductValidator works fine.
The problem is UserValidator is never called.
InitBinder method is being called, but validation doesn't work.
At the same time everything works fine with products in ProductController.
Here's the code of user logic.
UserController
#Controller
#RequestMapping(path = "/users")
public class UserController {
private final UserService userService;
private final RoleService roleService;
private PasswordEncoder passwordEncoder;
#Autowired
public UserController(UserService userService, RoleService roleService, PasswordEncoder passwordEncoder) {
this.userService = userService;
this.roleService = roleService;
this.passwordEncoder = passwordEncoder;
}
#Autowired
#Qualifier("userValidator")
private UserValidator userValidator;
#InitBinder("user")
private void initBinder(WebDataBinder binder) {
binder.setValidator(userValidator);
binder.registerCustomEditor(Role.class, "roles", new RoleEditor(roleService));
}
...
#RequestMapping(path = "/save", method = RequestMethod.POST)
public ModelAndView submit(#ModelAttribute("user") #Valid User user,
BindingResult result) {
...
}
...
}
UserValidator
#Component("userValidator")
public class UserValidator implements Validator {
private final UserRepository userRepository;
private final RoleRepository roleRepository;
#Autowired
public UserValidator(UserRepository userRepository, RoleRepository roleRepository) {
this.userRepository = userRepository;
this.roleRepository = roleRepository;
}
#Override
public boolean supports(Class<?> paramClass) {
return User.class.equals(paramClass);
}
#Override
public void validate(Object obj, Errors errors) {
User user = (User) obj;
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "username", "username.required", "Enter username");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "firstName.required", "Enter user first name");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "lastName", "lastName.required", "Enter user last name");
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "password", "password.required", "Enter user password");
User userToFind = userRepository.findByUsername(user.getUsername()).orElse(new User());
if (Objects.isNull(user.getId()) && Objects.nonNull(userToFind.getId())) {
errors.rejectValue("username", "username.already.exist", "user with this username already exists");
}
if (Objects.isNull(user.getRoles())) {
errors.rejectValue("roles", "role.required", "role must be assigned");
}
Role adminRole = roleRepository.getAdminRole();
if (Objects.nonNull(user.getId())
&& Objects.nonNull(user.getRoles())
&& !user.getRoles().contains(adminRole)
&& userRepository.findUsersWithAdministratorRole().size() == 1) {
errors.rejectValue("roles", "admin.required", "at least one admin role must exist");
}
}
public ErrorMessage validateUserToDelete(UUID id) {
ErrorMessage errorMessage = new ErrorMessage();
List<String> errors = new ArrayList<>();
Set<User> admins = userRepository.findUsersWithAdministratorRole();
if (admins.size() == 1) {
errors.add(String.format("User with email %s is the one with Admin role. Impossible to delete last Admin user."
, userRepository.findById(id).get().getUsername()));
}
errorMessage.setErrors(errors);
return errorMessage;
}
}
User
#Entity
#Table(name = "users")
public class User {
private UUID id;
private String username;
private String password;
private String firstName;
private String lastName;
private BigDecimal money;
private Set<Role> roles;
private Set<Product> products;
#Id
#Type(type="org.hibernate.type.PostgresUUIDType")
#Column(name = "id", columnDefinition = "uuid")
#GeneratedValue(strategy = GenerationType.AUTO)
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
#Column(name = "username")
#NotEmpty
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "password")
#NotEmpty
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "first_name")
#NotEmpty
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "last_name")
#NotEmpty
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name = "money")
#DecimalMin(value = "0.0", inclusive = false)
#Digits(integer = 10, fraction = 2)
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal money) {
this.money = money;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.REFRESH})
#JoinTable(
name = "users_roles",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "role_id") }
)
#NotNull
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.REFRESH})
#JoinTable(
name = "checkout",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "product_id") }
)
public Set<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return id.equals(user.id) && username.equals(user.username) && password.equals(user.password) && firstName.equals(user.firstName) && lastName.equals(user.lastName);
}
#Override
public int hashCode() {
return Objects.hash(id, username, password, firstName, lastName);
}
}
user.jsp
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="security" uri="http://www.springframework.org/security/tags" %>
<%# page contentType="text/html;charset=UTF-8" language="java" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<c:import url="${contextPath}/WEB-INF/jsp/header.jsp"/>
</head>
<body>
<c:import url="${contextPath}/WEB-INF/jsp/navibar.jsp"/>
<div class="container">
<div class="row">
<security:authorize access="hasRole('ROLE_ADMIN')">
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group me-2" role="group" aria-label="Second group">
Back to users
</div>
</div>
</security:authorize>
</div><br>
<form:form action="/users/save" method="post" modelAttribute="user">
<div class="form-group">
<div class="row">
<form:label path="id">User ID:</form:label><br>
<form:input path="id" type="UUID" readonly="true" class="form-control" id="id" placeholder="User ID" name="id" value="${user.id}"/>
<br>
<form:label path="username">username (email address):</form:label><br>
<form:input path="username" type="text" class="form-control" id="username" placeholder="Enter username" name="username" value="${user.username}"/>
<form:errors path="username" cssClass="error"/>
<br>
<form:label path="password">Password:</form:label><br>
<form:input path="password" type="text" class="form-control" id="password" placeholder="Enter password" name="password" value="${user.password}"/>
<form:errors path="password" cssClass="error"/>
<br>
<form:label path="firstName">First name:</form:label><br>
<form:input path="firstName" type="text" class="form-control" id="firstName" placeholder="Enter first name" name="firstName" value="${user.firstName}"/>
<form:errors path="firstName" cssClass="error"/>
<br>
<form:label path="lastName">First name:</form:label><br>
<form:input path="lastName" type="text" class="form-control" id="lastName" placeholder="Enter last name" name="lastName" value="${user.lastName}"/>
<form:errors path="lastName" cssClass="error"/>
<br>
<form:label path="money">Money:</form:label><br>
<form:input path="money" type="number" class="form-control" id="money" placeholder="Enter money" name="money" value="${user.money}"/>
<form:errors path="money" cssClass="error"/>
<br>
<security:authorize access="hasRole('ROLE_ADMIN')">
<form:label path="roles">Roles:</form:label><br>
<c:forEach items="${roles}" var="role">
<form:checkbox path="roles" id="${roles}" label="${role.name}" value="${role}"/></td>
</c:forEach>
<br>
<form:errors path="roles" cssClass="error"/><br><br>
</security:authorize>
</div>
<div class="row">
<div class="btn-toolbar" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group me-2" role="group" aria-label="Second group">
<form:button type="submit" value="Submit" class="btn btn-primary">Save</form:button>
</div>
</div>
</div>
</div>
</form:form>
</div>
</body>
</html>

If you look at the classname from your debugger com.intellias.testmarketplace.controller.UserController$$EnhancerBySpringCGLIB$$309171b7 you see the $$EnhancerBySpringCGLIB. That part indicates that a proxy is being generated by Spring. A proxy can be generated for various reasons but the most common one for controllers is security, the #PreAuthorize annotation comes to mind. Another option is the #Timed annotation to do monitoring on the controller.
As your initBinder method is private this will be invoked directly on the proxy and not on the actual bean instance. This is due to a class proxy being created, which works by extending your class. A method is being generated with the same signature and the interceptor is invoked and then the call is passed on to the actual method. However this will only work for public and protected methods not for private or final methods. Those will be directly invoked on the empty proxy (the fields are null as that doesn't need the dependencies).
As your method is private it is invoked on the proxy. The proxy doesn't have the fields set, so the userValidator is null. So effectivly there is no Validator being set on the WebDataBinder and thus no validation will and can be done.
To fix, make the method public (or protected) so that it will properly be called on the actual bean and not the proxy.
For the future and as a rule of thumb you probably want your methods with annotations in a controller to be public anyway instead of `private.

The issue was in private access modifier for initBinder method combined with #PreAuthorize annotation on some UserController methods.
Many thanks to #M.Deinum for patience and help.

Related

Add an object using SpringBoot and Thymeleaf

I am building an event website using Springboot and I am trying to make the new_event page where you should create a new event. But aftetr completing the form and click the button "Add Event", there is nothing happening. What is the issue?
new_event HTML is:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
layout:decorate="~{layouts/default}">
<head>
<title>Create event</title>
</head>
<body>
<div layout:fragment="content">
<h1>Create a new event</h1>
<p> Complete the following fields to add an event . * - required field </p>
<form action="#" th:action="#{/events}" th:object="${events}" method="post">
<div class="form-group" th:classappend="${#fields.hasErrors('name')}? has-error">
<label for="name">Name *:</label>
<input class="form-control" type="text" th:field="*{name}" name="name" id="name" placeholder="Max 250 chars" autofocus="autofocus" required/>
<p class="text-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}">errors</p>
<label for="ev_venue">Venue *:</label>
<input class="form-control" type="text" th:field="*{venue}" name="ev_venue" id="ev_venue" autofocus="autofocus" />
<label for="ev_date">Date *:</label>
<input class="form-control" type="date" th:field="*{date}" name="ev_date" id="ev_date" autofocus="autofocus" />
<label for="ev_time">Time :</label>
<input class="form-control" type="time" th:field="*{time}" name="ev_time" id="ev_time" autofocus="autofocus" />
<label for="ev_descr">Description :</label>
<input class="form-control" type="text" th:field="*{description}" name="ev_descr" id="ev_descr" placeholder="Max 500 chars" autofocus="autofocus" />
</div>
</form>
<button class="btn btn-primary" type="submit"><i class="fas fa-plus" aria-hidden="true"></i> Add Event</button>
<a class="btn btn-warning" role="button" href="/events"><i class="fas fa-ban" aria-hidden="true"></i> Cancel</a>
</form>
</div>
</body>
</html>
Event Controller is :
#Controller
#RequestMapping(value = "/events", produces = { MediaType.TEXT_HTML_VALUE })
public class EventsController {
#Autowired
private EventService eventService;
#GetMapping("/new_event")
public String newEvent(Model model) {
if (!model.containsAttribute("events")) {
model.addAttribute("events", new Event());
}
return "events/new_event";
}
#PostMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public String createEvent(#RequestBody #Valid #ModelAttribute Event event, BindingResult errors,
Model model, RedirectAttributes redirectAttrs) {
if (errors.hasErrors()) {
model.addAttribute("events", event);
return "events/new_event";
}
eventService.save(event);
redirectAttrs.addFlashAttribute("ok_message", "New event added.");
return "redirect:/events";
}
}
EventController API is:
#RestController
#RequestMapping(value = "/api/events", produces = { MediaType.APPLICATION_JSON_VALUE, MediaTypes.HAL_JSON_VALUE })
public class EventsControllerApi {
private static final String NOT_FOUND_MSG = "{ \"error\": \"%s\", \"id\": %d }";
#Autowired
private EventService eventService;
#Autowired
private EventModelAssembler eventAssembler;
#GetMapping("/new_event")
public ResponseEntity<?> newEvent() {
return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).build();
}
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<?> createEvent(#RequestBody #Valid Event event, BindingResult result) {
if (result.hasErrors()) {
return ResponseEntity.unprocessableEntity().build();
}
Event newEvent = eventService.save(event);
EntityModel<Event> entity = eventAssembler.toModel(newEvent);
return ResponseEntity.created(entity.getRequiredLink(IanaLinkRelations.SELF).toUri()).build();
}
}
And the Event class:
#Entity
#Table(name = "events")
public class Event {
#Id
private long id;
#JsonFormat(shape = JsonFormat.Shape.STRING)
#DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate date;
#JsonFormat(shape = JsonFormat.Shape.STRING)
#DateTimeFormat(pattern = "HH:mm")
private LocalTime time;
#Persistent
#NotEmpty(message = "The event must have a name.")
#Size(max = 250, message = "The name of the event must have 250 characters or less.")
private String name;
#ManyToOne
#Persistent
private Venue venue;
private String description;
public Event() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public LocalTime getTime() {
return time;
}
public void setTime(LocalTime time) {
this.time = time;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Venue getVenue() {
return venue;
}
public void setVenue(Venue venue) {
this.venue = venue;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

Why I Can't Do Mapping using Many-To-One

Do anyone knows why I can't do mapping using many-to-one?
This is my model
#Entity(name="trxrawatjalan")
public class Rawatjalan implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int idRawatjalan;
#Column(nullable = false, insertable = false, updatable = false)
private int idPasien;
#Column(nullable = false, insertable = false, updatable = false)
private int idDokter;
#Column(nullable = false, insertable = false, updatable = false)
private int idTreatment;
public Rawatjalan() {
}
public Rawatjalan(int idRawatjalan) {
this.idRawatjalan = idRawatjalan;
}
public int getIdPasien() {
return idPasien;
}
public void setIdPasien(int idPasien) {
this.idPasien = idPasien;
}
public int getIdDokter() {
return idDokter;
}
public void setIdDokter(int idDokter) {
this.idDokter = idDokter;
}
public int getIdTreatment() {
return idTreatment;
}
public void setIdTreatment(int idTreatment) {
this.idTreatment = idTreatment;
}
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name= "idPasien", nullable = false)
private Pasien pasien;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name= "idDokter", nullable = false)
private Dokter dokter;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name= "idTreatment", nullable = false)
private Treatment treatment;
public int getIdRawatjalan() {
return idRawatjalan;
}
public void setIdRawatjalan(int idRawatjalan) {
this.idRawatjalan = idRawatjalan;
}
#Override
public String toString () {
return "Rawatjalan{" +
"idRawatjalan=" + idRawatjalan +
'}';
This is my trxindex.jsp:
<c:forEach var="rawatjalan" items="${rawatjalans}">
<tr>
<td>${rawatjalan.idRawatjalan}</td>
<td>${rawatjalan.pasien.idPasien}</td>
<td>${rawatjalan.dokter.idDokter}</td>
<td>${rawatjalan.treatment.idTreatment}</td>
<td><span class="glyphicon glyphicon-pencil"></span></td>
<td><span class="glyphicon glyphicon-trash"></span></td>
</tr>
</c:forEach>
</tbody>
</table>
</div>
</div>
<form class="form-horizontal" method="POST" action="save-treatment">
<input type="hidden" name="idRawatjalan" value="${rawatjalan.idRawatjalan}"/>
<div class="form-group">
<label class="control-label col-md-3">Id Pasien</label>
<div class="col-md-7">
<input type="text" class="form-control" name="rawatjalan.pasien.idPasien" value="${rawatjalan.pasien.idPasien}"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">id Dokter</label>
<div class="col-md-7">
<input type="text" class="form-control" name="rawatjalan.dokter.idDokter" value="${rawatjalan.dokter.idDokter}"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">id Treatment</label>
<div class="col-md-7">
<input type="text" class="form-control" rows="3" name="rawatjalan.treatment.idTreatment" value="${rawatjalan.treatment.idTreatment}"/>
</div>
</div>
This is my controller:
#Autowired
private TrxService trxService;
#GetMapping("/data-rawatjalan")
public String dataRawatjalans(HttpServletRequest request){
request.setAttribute("rawatjalans", trxService.findAll());
request.setAttribute("mode", "MODE_TASKS");
return "indextrx";
}
#GetMapping("/new-rawatjalan")
public String newRawatjalan(HttpServletRequest request){
request.setAttribute("mode", "MODE_NEW");
return "indextrx";
}
#PostMapping("/save-rawatjalan")
public String saveRawatjalan(#ModelAttribute Rawatjalan rawatjalan, BindingResult bindingResult, HttpServletRequest request){
trxService.save(rawatjalan);
request.setAttribute("rawatjalans", trxService.findAll());
request.setAttribute("mode", "MODE_TASKS");
return "indextrx";
}
#GetMapping("/update-rawatjalan")
public String updateRawatjalan(#RequestParam int idRawatjalan, HttpServletRequest request){
request.setAttribute("rawatjalan", trxService.findRawatjalan(idRawatjalan));
request.setAttribute("mode", "MODE_UPDATE");
return "indextrx";
}
#GetMapping("/delete-rawatjalan")
public String deleteRawatjalan(#RequestParam int idRawatjalan, HttpServletRequest request){
trxService.delete(idRawatjalan);
request.setAttribute("rawatjalans", trxService.findAll());
request.setAttribute("mode", "MODE_TASKS");
return "indextrx";
}
This is my service:
#Service
#Transactional
public class TrxService {
private final TrxinapRepository trxinapRepository;
public TrxService(TrxinapRepository trxinapRepository) {
this.trxinapRepository = trxinapRepository;
}
public List<Rawatjalan> findAll(){
List<Rawatjalan> rawatjalans = new ArrayList<>();
for(Rawatjalan rawatjalan : trxinapRepository.findAll()){
rawatjalans.add(rawatjalan);
}
return rawatjalans;
}
public Rawatjalan findRawatjalan(int idRawatjalan){
return trxinapRepository.findOne(idRawatjalan);
}
public void save(Rawatjalan rawatjalan){
trxinapRepository.save(rawatjalan);
}
public void delete(int idRawatjalan){
trxinapRepository.delete(idRawatjalan);
}
}
My Repository
package bootsample.dao;
import bootsample.mod`enter code here`el.Rawatjalan;
import org.springframework.data.repository.CrudRepository;
public interface TrxinapRepository extends CrudRepository<Rawatjalan, Integer>{
}
2019-05-19 03:10:50.977 ERROR 1712 --- [nio-8030-exec-4] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [An exception occurred processing JSP page /WEB-INF/jsp/indextrx.jsp at line 77
74:
75:
76: ${rawatjalan.idRawatjalan}
77: ${rawatjalan.pasien.idPasien}
78: ${rawatjalan.dokter.idDokter}
79: ${rawatjalan.treatment.idTreatment}
80:
Stacktrace:] with root cause
javax.el.PropertyNotFoundException: Property 'pasien' not found on type bootsample.model.Rawatjalan

HTTP Status 400 – Bad Request - Spring MVC

i've got this error on my project.
HTTP Status 400 – Bad Request.
The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, invalid request message framing, or deceptive request routing).
InsertClient.jsp
<form:form action="/moldar/saveCliente/" method="POST" modelAttribute="cliente">
<div class="form-group">
<label for="exampleSelect1">Pais</label>
<form:select path="pais" class="form-control" id="pais" name="wwww">
<c:forEach var="lista" items="${listaPaises}">
<option value="${lista.id}">${lista.nome}</option>
</c:forEach>
</form:select>
</div>
<div class="form-group">
<label for="exampleSelect1">Estado</label>
<form:select path="estado" class="form-control" id="estado" name="qqqqq">
<option value="">Selecione um estado</option>
<c:forEach var="lista" items="${listaEstados}">
<option value="${lista.id}">${lista.nome}</option>
</c:forEach>
</form:select>
</div>
<div class="form-group">
<label for="exampleSelect1">Cidade</label>
<form:select path="cidade" class="form-control" id="cidade" name="batata">
<option value="null">Selecione uma cidade</option>
<c:forEach var="lista" items="${listaCidades}">
<option value="${lista.id}">${lista.nome}</option>
</c:forEach>
</form:select>
</div>
My Controllers
#RequestMapping(value = "/saveCliente", method = RequestMethod.POST)
public String adicionarCliente(#ModelAttribute("cliente") Cliente cliente) {
clienteDao.saveOrUpdate(cliente);
return "redirect:/clientes";
}
#RequestMapping(value = "/addCliente", method = RequestMethod.GET, headers = "Accept=application/json")
public String inserirCliente(Model model) {
List<Estado> listaEstados = estadoDao.list(null);
List<Cidade> listaCidades = cidadeDao.list(null);
List<Pais> listaPaises = paisDao.list(null);
model.addAttribute("listaPaises", listaPaises);
model.addAttribute("listaEstados", listaEstados);
model.addAttribute("pais", new Pais());
model.addAttribute("cliente", new Cliente());
model.addAttribute("estado", new Estado());
model.addAttribute("cidade", new Cidade());
model.addAttribute("listaCidades", listaCidades);
return "inserirCliente";
}
Model
#Entity
#Table (name= "clientes")
public class Cliente {
#Id
#GeneratedValue (strategy = GenerationType.IDENTITY)
#Column
private Integer id;
#Column
private String nome;
#Column
private String cpf;
#OneToOne
#JoinColumn (name="pais")
private Pais pais;
#OneToOne
#JoinColumn (name="estado")
private Estado estado;
#OneToOne
#JoinColumn (name="cidade")
private Cidade cidade;
#Column
private String logradouro;
#Column
private String numero;
#Column
private String cep;
#Column
private String email;
I have trying everything.
Can someone help me ? Please ?
In your Contoller this line of code
public String adicionarCliente(#ModelAttribute("cliente") Cliente cliente)
In your Cliente class the variables like pais
<form:select path="pais" class="form-control" id="pais" name="wwww">
you cannot bind this path="pais" to Cliente class variable pais , Because pais is not a String Type it is an Object type.
You can Create another class to Bind the input Selection Options to the variables.
class Client {
private String pais;
private String estado;
private String cidade;
public String getPais() {
return pais;
}
public void setPais(String pais) {
this.pais = pais;
}
public String getEstado() {
return estado;
}
public void setEstado(String estado) {
this.estado = estado;
}
public String getCidade() {
return cidade;
}
public void setCidade(String cidade) {
this.cidade = cidade;
}
}

Spring binding checkbox with Set of Objects

I would like to build a form to save an User. I have 2 tables, User and UserRole as described in Spring Security. To save an user I need to create a User Object that contains a field Set. I want to create a list of checkboxes and map them into an Set of UserRoles, but I don't know how to map them with checkboxes. I have the following classes:
#Controller
public class UserController {
#Autowired
IUserService userService;
/** Default GET form handler for users, in submission will call saveRegistration */
#RequestMapping(value="/createuser", method=RequestMethod.GET)
public String createUser(Model model) {
// User form will be bind to this User object
model.addAttribute("user", new User());
// Code about adding the user roles to JSP?
// Maybe something like this?:
// User u = new User ("useruser","123456",false);
// Set<UserRole> roles = new HashSet<UserRole>();
// roles.add(new UserRole(u,"ROLE_ADMIN"));
// roles.add(new UserRole(u,"ROLE_USER"));
// model.addAttribute("roles", roles);
return "createuser";
}
/** This method will be called on form submission, handling POST request,
* It also validates the user input */
#RequestMapping(value="/createuser", method=RequestMethod.POST)
public String doCreateUser(Model model, #Valid User user, BindingResult result) {
if(result.hasErrors()) {
return "createuser";
}
userService.createUser(user,user.getUserRole()) //createUser(User user, Set<UserRole> role)
return "success";
}
}
My JSP:
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%# taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<link rel="stylesheet" type="text/css" href="resources/css/createuser.css" />
</head>
<body onload='document.createUserForm.username.focus();'>
<sf:form name="createUserForm" method="post"
action="${pageContext.request.contextPath}/createuser"
commandName="user">
<table class="formtable">
<tr>
<td class="label">Username:</td>
<td><sf:input class="control" path="username" name="username"
type="text" /><br />
<div class="error">
<sf:errors path="username"></sf:errors>
</div></td>
</tr>
<tr>
<td class="label">Role:</td>
<td>
<ul>
<sf:checkboxes element="li" path="userRole" items="${roles}"></sf:checkboxes>
</ul></td>
</tr>
<tr>
<td class="label">Password:</td>
<td><sf:input class="control" path="password" name="password"
type="password" />
<div class="error">
<sf:errors path="password"></sf:errors>
</div></td>
</tr>
<tr>
<td class="label">Confirm Password:</td>
<td><input class="control" name="confirmpass" type="password" />
<div class="error">
<sf:errors path="password"></sf:errors>
</div></td>
</tr>
<tr>
<td class="label"></td>
<td><input class="control" value="Create account" type="submit" /></td>
</tr>
</table>
</sf:form>
User Role:
public class UserRole {
private Integer userRoleId;
private User user;
private String role;
public UserRole () {
}
public UserRole(User user, String role) {
this.user = user;
this.role = role;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "user_role_id",
unique = true, nullable = false)
public Integer getUserRoleId() {
return userRoleId;
}
public void setUserRoleId(Integer userRoleId) {
this.userRoleId = userRoleId;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "username", nullable = false)
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
#Column(name = "role", nullable = false, length = 45)
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String toString () {
return role;
}
}
And User:
public class User {
#NotNull
#NotBlank(message="Username cannot be blank.")
#Size(min=4, max=15, message="Username must be between 4 and 15 characters long.")
#Pattern(regexp="^\\w{6,}$", message="Username can only consist of numbers, letters and the underscore character.")
private String username;
#NotBlank(message="Password cannot be blank.")
#Pattern(regexp="^\\S+$", message="Password cannot contain spaces.")
#Size(min=6, message="Username must be longer than 6 characters.")
private String password;
//private String confirmPassword;
private boolean enabled;
private Set<UserRole> userRole = new HashSet<UserRole>(0);
public User() {
}
public User(String username, String password, boolean enabled) {
this.username = username;
this.password = password;
this.enabled = enabled;
}
public User(String username, String password,
boolean enabled, Set<UserRole> userRole) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.userRole = userRole;
}
#Id
#Column(name = "username", unique = true, nullable = false, length = 45)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "password", nullable = false, length = 60)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Column(name = "enabled", nullable = false)
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
public Set<UserRole> getUserRole() {
return userRole;
}
public void setUserRole(Set<UserRole> userRole) {
this.userRole = userRole;
}
/*public String getConfirmPassword() {
return confirmPassword;
}
public void setConfirmPassword(String confirmPassword) {
this.confirmPassword = confirmPassword;
}*/
}
Thanks in advance.
Refert this post, and i dont see the itemlabel and itemid attribute, which maps to userrole object.
also refer post
Found solution using Properties Editor. Here and here

Spring form send null model object to database

I want to send data from form to PostgreSQL. When I send data by form, hibernate save (by save() method) blank record .. I did it manually (for test) without using form and then everything is ok.
Spitter.class (entity for user)
#Entity
#Table(name="spitter")
public class Spitter implements Serializable {
private static final long serialVersionUID = 829803238866007413L;
#Id
//#SequenceGenerator(name = "hibernate_sequence")
#GeneratedValue(strategy=GenerationType.AUTO) #Column(name="spitter_id")
private Long id;
#Column(unique=true) #Size(min=3, max=20) #Pattern(regexp = "^[a-zA-Z0-9]+$", message="Nie poprawna nazwa uzytkownika.")
private String username;
#Size(min=5, max=15, message="Haslo musi miec minimum 5 znakow.")
private String password;
#Size(min=3, max=25, message="Blad w imieniu i nazwisku.")
private String fullName;
#OneToMany(mappedBy="spitter")
private List<Spittle> spittles;
#Email(message="Nie poprawny adres email.")
private String email;
private boolean updateByEmail;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public List<Spittle> getSpittles() {
return spittles;
}
public void setSpittles(List<Spittle> spittles) {
this.spittles = spittles;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public void setUpdateByEmail(boolean updateByEmail) {
this.updateByEmail = updateByEmail;
}
public boolean isUpdateByEmail() {
return updateByEmail;
}
#Override
public boolean equals(Object obj) {
Spitter other = (Spitter) obj;
return other.fullName.equals(fullName) && other.username.equals(username) && other.password.equals(password);
}
#Override
public int hashCode() {
// TODO Auto-generated method stub
return super.hashCode();
}
}
SpitterController.class
createSpitterProfile - shows form (edit.jsp) and sends model object (spitter) to form
addSpitterFromForm - receives binding data from form and save it to database and redirects to simply user profile
showSpitterProfile - there is of course null model object exception
#Controller
#RequestMapping("/spitters")
public class SpitterController {
private final SpitterService spitterService;
#Inject //#Autowired
public SpitterController(SpitterService spitterService) {
this.spitterService = spitterService;
}
//...
#RequestMapping(method = RequestMethod.GET, params = "new")
public String createSpitterProfile(Model model) {
model.addAttribute("spitter", new Spitter());
return "spitters/edit";
}
#RequestMapping(method = RequestMethod.POST)
public String addSpitterFromForm(#Valid Spitter spitter, BindingResult bindingResult) {
if(bindingResult.hasErrors())
return "spitters/edit";
spitterService.saveSpitter(spitter);
return "redirect:/spitters/" + spitter.getUsername();
}
#RequestMapping(value="/{username}", method = RequestMethod.GET)
public String showSpitterProfile(#PathVariable String username, Model model) {
model.addAttribute(spitterService.getSpitter(username));
return "spitters/view";
}
edit.jsp (registration form for new user (Spitter))
<%# taglib prefix="sf" uri="http://www.springframework.org/tags/form"%>
<%# taglib prefix="s" uri="http://www.springframework.org/tags"%>
<div>
<h2>New account test</h2>
<sf:form method="POST" modelAttribute="spitter"
enctype="multipart/form-data">
<fieldset>
<table>
<tr>
<th><sf:label path="fullName">Full name:</sf:label></th>
<td><sf:input path="fullName" size="15" /><br/>
<sf:errors path="fullName" cssClass="error" />
</td>
</tr>
<tr>
<th><sf:label path="username">Username:</sf:label></th>
<td><sf:input path="username" size="15" maxlength="15" />
<small id="username_msg">No spaces, please.</small><br/>
<sf:errors path="username" cssClass="error" />
</td>
</tr>
<tr>
<th><sf:label path="password">Password:</sf:label></th>
<td><sf:password path="password" size="30"
showPassword="true"/>
<small>6 characters or more (be tricky!)</small><br/>
<sf:errors path="password" cssClass="error" />
</td>
</tr>
<tr>
<th><sf:label path="email">Email Address:</sf:label></th>
<td><sf:input path="email" size="30"/>
<small>In case you forget something</small><br/>
<sf:errors path="email" cssClass="error" />
</td>
</tr>
<tr>
<th></th>
<td>
<sf:checkbox path="updateByEmail"/>
<sf:label path="updateByEmail">Send me email updates!</sf:label>
</td>
</tr>
<tr>
<th></th>
<td>
<input name="commit" type="submit"
value="I accept. Create my account." />
</td>
</tr>
</table>
</fieldset>
</sf:form>
</div>
and blank saved record to Postgres..
Try adding #modelattribute in this method .It fill fetch the required model object.
#RequestMapping(method = RequestMethod.POST)
public String addSpitterFromForm(**#ModelAttribute("spitter")** #Valid Spitter spitter, BindingResult bindingResult) {
if(bindingResult.hasErrors())
return "spitters/edit";
spitterService.saveSpitter(spitter);
return "redirect:/spitters/" + spitter.getUsername();
}
and just to check if it is getting the values from form,syso some values like syso(spitter.getUserName) to check if values are coming.
ALso, I believe that you are making a constructor and passing service to it ,so there is no need of #Inject
#Inject //#Autowired///Why are you injecting it if it is a constructor?
public SpitterController(SpitterService spitterService) {
this.spitterService = spitterService;
}
You have enctype="multipart/form-data in your FORM,
Check that you have something like that in your App-servlet.xml:
<bean id="multipartResolver" class=
"org.springframework.web.multipart.commons.CommonsMultipartResolver"
p:maxUploadSize="500000" />

Categories