load form Fragment thymelef ajax spring boot - ajax

I am working with spring boot and thymeleaf, I want to load a fragment with ajax. It loads well, but when sending it the fragment object is not sent with the main object.
Here is the code that I use.
Model
#Entity
#Table(name = "solicitudes")
public class Solicitud {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_solicitud")
private Integer id;
#Column(name = "descripcion")
private String descripcion;
#ManyToOne
#JoinColumn(name = "id_persona") //,nullable=false
private Persona persona;
.
.
.
}
#Entity
#Table(name = "personas")
public class Persona {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id_persona")
private Long id;
#Column(name = "razon_social")
private String razonSocial;
#Column(name = "dni")
private Integer dni;
.
.
.
}
Controller
#RequestMapping(value = "/solicitudes/nuevo", method = RequestMethod.GET)
public ModelAndView newGet() {
ModelAndView modelAndView = new ModelAndView();
Solicitud solicitud = new Solicitud();
modelAndView.addObject("solicitud", solicitud);
modelAndView.setViewName("solicitudes/solicitudForm");
return modelAndView;
}
//Controller return fragment
#RequestMapping(value = "/solicitudes/{dni}", method = RequestMethod.GET)
public String showPersonaFragment(Model model, #PathVariable("dni") String dni) {
Persona persona = personaService.findPersonaByDni(Integer.parseInt(dni));
model.addAttribute("obraSociales", obraSocialService.listAllObraSocial());
model.addAttribute("pcias", pciaService.listAllProvincia());
model.addAttribute("localidades", localidadService.getAllLocalidades());
model.addAttribute("nivelesIntruccion", nivelIntruccionServices.listAllNivelInstruccion());
model.addAttribute("persona", persona);
return "solicitudes/formPersonaFrag:: header";
}
solicitudForm
<div class="form-group">
<div class="col-sm-5">
<label for="dni">Nro. de Documento</label>
<input type="number" id="dni" placeholder="Nro. de Documento."
class="form-control" required="required"/>
</div>
<div class="col-sm-5">
<br> <p id="mensajePersona" class="help-block"></p>
</div>
</div>
<div class="tab-pane" id="datosPersonales">
<div id="personaFragment">
<div class="alert alert-danger" role="alert">
<span>Debe ingresar el Nro. de Documento</span>
</div>
</div>
<div class="row margin-bottom"></div>
</div>
formPersonaFrag
<div th:fragment="formPersonaFrag">
<div th:fragment="header">
<div>
<fieldset id="datos_personales">
<div>
<input type="hidden" th:field="*{persona.id}" class="form-control" />
</div>
<div class="form-group">
<div class="col-sm-9">
<label for="razonSocial">Apellido y Nombre</label>
<div th:if="${persona.razonSocial==null}">
<input type="text" th:field="*{persona.razonSocial}" placeholder="Apellido y Nombre"
class="form-control" required="required" />
<div class="has-error">
<label th:if="${#fields.hasErrors('persona.razonSocial')}"
th:errors="*{persona.razonSocial}"
class="control-label"></label>
</div>
</div>
<div th:if="${persona.razonSocial!=null}">
<span th:text="*{persona.razonSocial}" ></span>
</div>
</div>
</div>
</fieldset>
</div>
</div> </div>
Ajax load fragment
$('#dni').change(function (e) {
var datos = $("#dni").val();
var url = '/solicitudes/' + datos;
console.log(url);
$("#personaFragment").load(url,$("#personaFragment").serialize());
$.ajax({
type: "GET",
contentType: "application/json",
url: "/api/persona/dni/" + datos,
data: JSON.stringify(datos),
dataType: 'json',
cache: false,
timeout: 600000,
success: function (data) {
$('#mensajePersona').empty();
},
error: function (e) {
$('#mensajePersona').empty();
console.log("ERROR : ", e);
}
});
in debug object solicitud.persona is null
debug app

Related

How to validate a form with binding result?

I have a simple form to save an User and I can't get it to show the error messages
I have the exact same structure for saving "Customer" and it works, but when I try to replicate it to User It doesn't work
My log error:
2019-08-21 17:07:14.521 WARN 11332 --- [nio-8080-exec-8]
.w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused
by handler execution: org.springframework.validation.BindException:
org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'user' on field 'password': rejected value
[123]; codes
[Size.user.password,Size.password,Size.java.lang.String,Size];
arguments
[org.springframework.context.support.DefaultMessageSourceResolvable:
codes [user.password,password]; arguments []; default message
[password],2147483647,6]; default message [A senha deve conter pelo
menos 6 caracteres.]
User controllers:
#GetMapping("/{customerId}/createUser")
public ModelAndView userForm(#PathVariable(value = "customerId", required
= false) Long customerId,
#RequestParam(value = "userId", required = false) Long userId,
Model model) {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
Optional<Users> authenticatedUserOptional =
userRepository.findByEmail(authentication.getName());
model.addAttribute("userLogedIsAdmin",
authenticatedUserOptional.get().getIsAdmin());
if (authentication == null || !authentication.isAuthenticated()) {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
if (!authenticatedUserOptional.isPresent()) {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
if (customerId != null) {
Optional<Customers> customerOptional =
customerRepository.findById(customerId);
Customers customer = customerOptional.get();
model.addAttribute("customer", customer);
if (userId != null) {
Users existingUser = userRepository.findById(userId).get();
if (existingUser.getEnabled()) {
existingUser.setUserStatus(UserStatus.ATIVO);
} else {
existingUser.setUserStatus(UserStatus.INATIVO);
}
model.addAttribute("user", existingUser);
} else {
model.addAttribute("user", new Users());
}
ModelAndView mv = new ModelAndView("customerNewUser");
return mv;
} else {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
}
#PostMapping("/{customerId}/createUser")
public ModelAndView saveUser(#PathVariable(value = "customerId", required
= true) Long customerId,
#ModelAttribute(name = "user") #Valid Users user,
RedirectAttributes redirectAttributes,
BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return userForm(customerId, user.getId(), new Model() {
#Override
public Model mergeAttributes(Map<String, ?> attributes) {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean containsAttribute(String attributeName) {
// TODO Auto-generated method stub
return false;
}
#Override
public Map<String, Object> asMap() {
// TODO Auto-generated method stub
return null;
}
#Override
public Model addAttribute(String attributeName, Object
attributeValue) {
// TODO Auto-generated method stub
return null;
}
#Override
public Model addAttribute(Object attributeValue) {
// TODO Auto-generated method stub
return null;
}
#Override
public Model addAllAttributes(Map<String, ?> attributes) {
// TODO Auto-generated method stub
return null;
}
#Override
public Model addAllAttributes(Collection<?> attributeValues)
{
// TODO Auto-generated method stub
return null;
}
});
}
// Encrypt password
if (user.getPassword().equals(user.getMatchPassword())) {
user.setPassword(encoder.encode(user.getPassword()));
user.setCustomerId(customerId);
user.setEventDescription("User Admin creation");
Users returnedUser = userService.save(user);
List<Authorities> authorities = new ArrayList<Authorities>();
Authorities auth = new Authorities(new
AuthoritiesPK(returnedUser.getId(), "ROLE_CLI_ADM"), returnedUser,
"ROLE_CLI_ADM");
authorities.add(auth);
returnedUser.setAuthorities(authorities);
returnedUser.setEventDescription("Add Admin role");
for (int i = 0; i < returnedUser.getAuthorities().size(); i++) {
authorityService.save(returnedUser.getAuthorities().get(i));
}
userService.save(returnedUser);
ModelAndView mv = new ModelAndView("redirect:/customers/" +
customerId);
return mv;
} else {
ModelAndView mv = new ModelAndView("accessDenied");
return mv;
}
}
form html:
<div class="card mb-3">
<div class="card-header"
th:text="${user?.id} ? #{editUser} : #{newUser}">
<i class="fas fa-table"></i>
</div>
<div class="card-body">
<form
th:action="#{${user?.id} ? '/customers/' + ${customer.id} + '/createUser/' + ${user.id} : '/customers/' + ${customer.id} + '/createUser/'}"
th:object="${user}" action="#" method="post">
<div class="alert alert-danger" th:if="${#fields.hasAnyErrors()}">
<div th:each="detailedError : ${#fields.detailedErrors()}">
<span th:text="${detailedError.message}"></span>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{firstname} + ':'">Firstname:</label>
</div>
<div class="col-md-4">
<input type="text" id="firstname" name="firstname"
th:value="${user?.firstname} ? ${user?.firstname} : ''"
class="form-control" th:placeholder="#{firstname}"
required="required" autofocus="autofocus"
th:field="*{firstname}" />
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{surname} + ':'">Surname:</label>
</div>
<div class="col-md-4">
<input type="text" id="surname" name="surname"
th:value="${user?.surname} ? ${user?.surname} : ''"
class="form-control" th:placeholder="#{surname}"
autofocus="autofocus" />
</div>
</div>
</div>
<div class="form-group">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{email} + ':'">Email:</label>
</div>
<div class="col-md-4">
<input th:placeholder="#{email}" required="required"
autofocus="autofocus" id="email" class="form-control"
type="text" th:value="${user?.email} ? ${user?.email} : ''"
name="email" th:field="*{email}" />
</div>
</div>
</div>
<div class="form-group" th:if="!${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{password} + ':'">Password:</label>
</div>
<div class="col-md-4">
<input type="password" id="password" name="password"
class="form-control" th:placeholder="#{password}"
required="required" autofocus="autofocus"
th:field="*{password}" />
</div>
</div>
</div>
<div class="form-group" th:if="!${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{passwordConfirmation} + ':'">Password
confirmation:</label>
</div>
<div class="col-md-4">
<input type="password" id="matchPassword" name="matchPassword"
class="form-control" th:placeholder="#{password}"
required="required" autofocus="autofocus"
th:field="*{matchPassword}" />
</div>
</div>
</div>
<div class="form-group" th:if="${user?.id}">
<div class="form-row">
<div class="col-md-5">
<label class="text-right label-control"
th:text="#{userStatus} + ':'">Status:</label>
</div>
<div class="col-md-3">
<select class="form-control form-control" id="userStatus"
name="userStatus">
<option
th:each="userStatus : ${T(br.com.macrosul.stetho.entity.UserStatus).values()}"
th:text="${userStatus}" th:value="${userStatus}"
th:selected="${user.userStatus} eq ${userStatus}"></option>
</select>
</div>
</div>
</div>
<div class="form-group" id="saveDiv">
<div class="form-row">
<div class="col-md-5"></div>
<div class="col-md-2">
<a class="btn-nounderline" href="#"> <input type="submit"
class="btn btn-md btn-block" value="Save"
th:value="${user?.id} ? #{updateUser} : #{save}" id="save" />
</a>
</div>
</div>
</div>
</form>
</div>
</div>
part of my model:
#Entity
public class Users extends BaseEntity {
private static final long serialVersionUID = -1667698094711992210L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"users_seq")
#SequenceGenerator(name = "users_seq", sequenceName = "users_seq",
allocationSize = 50, initialValue = 1)
#JsonProperty(access = Access.READ_ONLY)
private Long id;
#NotBlank(message = "E-mail não pode estar em branco.")
#NotNull(message = "E-mail deve ser informado.")
#Email(message = "Formato inválido de E-mail.")
#Column(nullable = false, unique = true)
private String email;
#JsonProperty(access = Access.WRITE_ONLY)
#Size(min=6, message="A senha deve conter pelo menos 6 caracteres.")
#NotNull(message = "A senha deve ser informada.")
#NotBlank(message = "A senha não pode estar em branco.")
#NotEmpty(message = "A senha não pode estar vazia.")
#Column(nullable = false)
private String password;
#JsonIgnore
#Transient
private String matchPassword;
#JsonIgnore
#Column(nullable = false)
private Boolean enabled = true;
#NotNull(message = "O nome deve ser informada.")
#NotBlank(message = "O nome não pode estar em branco.")
#NotEmpty(message = "O nome não pode estar vazia.")
#Column(nullable = false)
private String firstname;
private String surname;
#Column(nullable = true)
private Long customerId;
#JsonIgnore
#Transient
private Boolean isAdmin;
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER, mappedBy = "user")
private List<Authorities> authorities = new ArrayList<>();
#Enumerated(EnumType.STRING)
#Transient
private UserStatus userStatus;
}
I simply can't understand why it does not show the error message, I'm pretty sure what's logged is not en error itself... Any help would be appreciated!
Might not be what is failing, but bindingresult has to follow the parameter it is validating. You can see more details on the answers here
So change:
public ModelAndView saveUser(#PathVariable(value = "customerId", required = true) Long customerId,
#ModelAttribute(name = "user") #Valid Users user, RedirectAttributes redirectAttributes,
BindingResult bindingResult) { ... }
To:
public ModelAndView saveUser(#PathVariable(value = "customerId", required = true) Long customerId,
RedirectAttributes redirectAttributes, #ModelAttribute(name = "user") #Valid Users user,
BindingResult bindingResult) { ... }

Why #Valid Class it fails if I create a repository?

I have this controller:
#RequestMapping(value="admin/departamento", method = RequestMethod.POST)
public ModelAndView departamentoGuardar(
#Valid Departamento departamento ,
BindingResult br
){
ModelAndView mav = new ModelAndView();
mav.setViewName("costos/departamento");
return mav;
}
...and it is working.
But, if I build a empty repository class:
#Repository("departamentoRepository")
public interface DepartamentoRepository extends JpaRepository<Departamento, Integer>{
}
My controller throws this when a put a String and only accepts int:
org.springframework.beans.TypeMismatchException: Failed to convert
value of type 'java.lang.String' to required type
'com.carrduci.gestionycontrol.model.Departamento'; nested exception is
org.springframework.core.convert.ConversionFailedException: Failed to
convert from type [java.lang.String] to type [java.lang.Integer] for
value 'asdf'; nested exception is java.lang.NumberFormatException: For
input string: "asdf" at
org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:80)
~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE] at
org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:52)
~[spring-beans-5.0.4.RELEASE.jar:5.0.4.RELEASE] at
org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:692)
~[spring-context-5.0.4.RELEASE.jar:5.0.4.RELEASE] at
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.createAttributeFromRequestValue(ServletModelAttributeMethodProcessor.java:141)
~[spring-webmvc-5.0.4.RELEASE.jar:5.0.4.RELEASE
My Class:
#Entity
#Table(name = "departamento")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Departamento.findAll", query = "SELECT d FROM Departamento d")})
public class Departamento implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "id_departamento")
private Integer idDepartamento;
#Size(max = 20)
#Column(name = "departamento")
private String departamento;
public Departamento() {
}
public Departamento(Integer idDepartamento) {
this.idDepartamento = idDepartamento;
}
public Integer getIdDepartamento() {
return idDepartamento;
}
public void setIdDepartamento(Integer idDepartamento) {
this.idDepartamento = idDepartamento;
}
public String getDepartamento() {
return departamento;
}
public void setDepartamento(String departamento) {
this.departamento = departamento;
}
#Override
public int hashCode() {
int hash = 0;
hash += (idDepartamento != null ? idDepartamento.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Departamento)) {
return false;
}
Departamento other = (Departamento) object;
if ((this.idDepartamento == null && other.idDepartamento != null) || (this.idDepartamento != null && !this.idDepartamento.equals(other.idDepartamento))) {
return false;
}
return true;
}
#Override
public String toString() {
return "com.carrduci.gestionycontrol.model.Departamento[ idDepartamento=" + idDepartamento + " ]";
}
}
UPDATE
<th:block th:include="fragments/encabezados :: encabezados"></th:block>
<div class="container">
<div class="row">
<div class="col-md-offset-4 col-sm-offset-0">
<div class="row">
<div class="col-sm-12"> <h4>Departamento</h4></div>
</div>
<div class="row">
<div class="col-sm-12 col-md-8 ">
<form th:action="${departamento.idDepartamento>0}?
#{/costos/admin/departamento/modificar}:
#{/costos/admin/departamento}"
method="post" th:object="${departamento}">
<div class="row">
<div class="form-group col-xs-12">
<input type="hidden" th:field="*{idDepartamento}">
<div class="input-group">
<span class="input-group-addon">Nombre</i></span>
<input class="form-control input-lg" type="text" th:field="*{departamento}">
<div class="alert alert-danger" th:if="${#fields.hasErrors('departamento')}" th:errors="*{departamento}" ></div>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12 text-right">
<a type="button" class="btn btn-danger BOTON_LIMPIAR" href="/index"> <span class=" glyphicon glyphicon-remove"></span> Cancelar</a>
<button type="submit" class="btn btn-success">
<span class="glyphicon glyphicon-floppy-save"></span>
<span th:text="${departamento.idDepartamento>0}?
#{Modificar}:
#{Guardar}">
</span>
</button>
</div>
</div>
</form>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-8 ">
<hr>
<th:block th:include="fragments/tabla :: tabla"></th:block>
</div>
</div>
</div>
</div>
</div>
<th:block th:include="fragments/pieDePagina :: pieDePagina"></th:block>

Unable to bind thymeleaf template and spring boot correctly

I am working on registration in spring boot with spring security and thymeleaf but for some reason the userForm.getUsername() gives null value during POST (see code below)
Person.java
#Entity#Table(name = "person")
public class Person {
#Id#Column(name = "username")
private String username;
#Column(name = "mobile")
private String mobile;
#JsonIgnore#Column(name = "password")
private String password;
#Transient#JsonIgnore
private String passwordConfirm;
#ManyToMany(cascade = CascadeType.ALL)#JoinTable(name = "bookandperson", joinColumns = #JoinColumn(name = "username"), inverseJoinColumns = #JoinColumn(name = "bookName"))
private List < Book > listOfBooks = new ArrayList < Book > ();
}
PersonController.java
#Controller
public class PersonController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model, Principal user) {
if (user != null) {
return "redirect:/";
}
model.addAttribute("userForm", new Person());
return "registration";
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute Person userForm, BindingResult bindingResult, Model model) {
System.out.println(userForm.getUsername()); //This is giving null value
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
System.out.println("binding result has errors");
return "registration";
}
userService.save(userForm);
securityService.autologin(userForm.getUsername(), userForm.getPasswordConfirm());
return "redirect:/";
}
registration.html
<head>
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
</head>
<body>
<nav th:replace="common/navbar :: common-navbar"/>
<div class="container mt-4">
<div class="row justify-content-center">
<div class="col-md-6 col-md-offset-6">
<form th:action="#{/registration}" method="post">
<div class="form-group row">
<label for="inputUsername" class="col-sm-2 col-form-label">Username</label>
<div class="col-md-6">
<input type="text" class="form-control" th:field="${userForm.username}" id="inputUsername" value="" placeholder="Username">
</div>
</div>
<div class="form-group row">
<label for="mobile" class="col-sm-2 col-form-label">Mobile</label>
<div class="col-md-6">
<input type="text" class="form-control" th:field="${userForm.mobile}" id="inputMobile" placeholder="Mobile">
</div>
</div>
<div class="form-group row">
<label for="inputPassword" class="col-sm-2 col-form-label">Password</label>
<div class="col-md-6">
<input type="password" class="form-control" th:field="${userForm.password}" id="inputPassword" placeholder="Password">
</div>
</div>
<div class="form-group row">
<label for="inputPasswordConfirm" class="col-sm-2 col-form-label">Confirm Password</label>
<div class="col-md-6">
<input type="password" class="form-control" th:field="${userForm.passwordConfirm}" id="inputPasswordConfirm" placeholder="Password">
</div>
</div>
<div class="form-group row">
<div class="offset-2 col-sm-10">
<button type="submit" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" class="btn btn-primary">Submit</button>
</div>
</div>
<small th:text="${error}"></small>
</form>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</body>
I binded correctly using th:field="${userForm.username}" but unable to find what is the problem here.
you have to take the model object into the form as follows
<form action="#" th:action="#{/registration}" th:object="${userForm}" method="post">
and add the getters and setters to the Person class

Spring Validation - Errors not displayed

I'm using a combination of Annotation validation and a Custom Validator
Object:
#Entity
#Table(name = "monitoringsystems")
public class MonitoringSystem {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NotNull(message = "Name must not be empty.")#Size(min=1, message="Name must not be empty.")
private String name;
#NotNull(message = "URL must not be empty.")#Size(min=1, message="Name must not be empty.")
private String url;
#NotNull(message = "Username must not be empty.")#Size(min=1, message="Name must not be empty.")
private String username;
#NotNull(message = "Password must not be empty.")#Size(min=1, message="Name must not be empty.")
private String password;
#NotNull(message = "Confirm Password must not be empty.")#Size(min=1, message="Name must not be empty.")
#Transient
private String passwordConfirm;
CustomValidator:
#Component
public class MonitoringSystemValidator implements Validator {
#Override
public boolean supports(Class<?> type) {
return MonitoringSystem.class.isAssignableFrom(type);
}
#Override
public void validate(Object o, Errors errors) {
MonitoringSystem monitoringSystem = (MonitoringSystem) o;
if(!monitoringSystem.getPassword().equals(monitoringSystem.getPasswordConfirm())){
errors.rejectValue("passwordConfirm", "Passwords are not equal.");
}
}
}
I initialize the custom validator in my controller and set the mapping for the form and the saving method.
Controller:
#Controller
public class MonitoringSystemController {
#Autowired
private MonitoringSystemValidator monitoringSystemValidator;
#InitBinder
public void dataBinding(WebDataBinder binder) {
binder.addValidators(monitoringSystemValidator);
}
#RequestMapping("/monitoringsystem/new")
public String newMonitoringSystem(Model model, HttpServletRequest request) {
MonitoringSystem monitoringSystem = new MonitoringSystem();
model.addAttribute("monitoringSystem", monitoringSystem);
request.getSession().setAttribute("anonymization", monitoringSystem.getAnonymization());
request.getSession().setAttribute("hosts", monitoringSystem.getHosts());
return "monitoringsystem/form";
}
#RequestMapping(value = "/monitoringsystem/save", method = RequestMethod.POST)
public String save(#Valid MonitoringSystem monitoringSystem, BindingResult result, HttpServletRequest request, Model model) {
if(result.hasErrors()){
model.addAttribute("monitoringSystem", monitoringSystem);
request.getSession().setAttribute("anonymization", request.getSession().getAttribute("anonymization"));
request.getSession().setAttribute("hosts", request.getSession().getAttribute("hosts"));
return "monitoringsystem/form";
}
//more code
In a first step I only want to change the CSS of my fields (I use bootstrap) so display the errors.
Form:
<form class="form-horizontal" th:modelAttribute="monitoringSystem" th:object="${monitoringSystem}" th:action="#{/monitoringsystem/save}" method="post">
<input type="hidden" th:field="*{id}"/>
<fieldset>
<legend>New Monitoring-System</legend>
<div class="form-group" th:classappend="${#fields.hasErrors('name')} ?: 'has-error has-danger'">
<label class="col-md-4 control-label" for="textinput">Systemname</label>
<div class="col-md-5">
<input th:field="*{name}" class="form-control input-md" type="text" />
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('url')} ?: 'has-error has-danger'">
<label class="col-md-4 control-label" for="textinput">URL</label>
<div class="col-md-5">
<input th:field="*{url}" class="form-control input-md" type="text" />
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('username')} ?: 'has-error has-danger'">
<label class="col-md-4 control-label" for="textinput">Username</label>
<div class="col-md-5">
<input th:field="*{username}" class="form-control input-md" type="text" />
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('password')} ?: 'has-error has-danger'">
<label class="col-md-4 control-label" for="textinput">Password</label>
<div class="col-md-5">
<input th:field="*{password}" class="form-control input-md" type="password" />
</div>
</div>
<div class="form-group" th:classappend="${#fields.hasErrors('passwordConfirm')} ?: 'has-error has-danger'">
<label class="col-md-4 control-label" for="textinput">Confirm Password</label>
<div class="col-md-5">
<input th:field="*{passwordConfirm}" class="form-control input-md" type="password" />
</div>
</div>
<div class="form-group">
<label class="col-md-4 control-label" for="singlebutton"></label>
<div class="col-md-4">
<a th:href="#{/monitoringsystem}" class="btn btn-default btn-small">Cancel</a> <button id="singlebutton" name="singlebutton" class="btn btn-primary btn-small">Submit</button>
</div>
</div>
</fieldset>
</form>
My validation is working correctly. The form is only saved if my fields are not null, the size is greater 1 and the password match. If not, my controller redirects me to the form.
The problem is, that my css don't change. So there must be a problem with my view-code or the errorBinding is not passed correctly to the view. But I can't find my mistake.
There was an error in my if condition which add the errorclasses. I had to change ${#fields.hasErrors('url')} ?: 'has-error has-danger' to ${#fields.hasErrors('*{name}')} ? 'has-error has-danger'

submitted form is not completely saved in the database

In my current spring project, one of the renderized forms is the follow:
<form id="Usuario" class="form" role="form" method="post" action="/caixa/Usuario/insert">
<li class="list-group-item">
<field-box>
<label>login</label>
<input type="text" name="login" id="login" class="form-control" />
</field-box>
</li>
<li class="list-group-item">
<field-box>
<label>senha</label>
<input type="password" name="senha" id="senha" class="form-control" />
</field-box>
</li>
<li class="list-group-item">
<field-box>
<label>nome</label>
<input type="text" name="nome" id="nome" class="form-control" />
</field-box>
</li>
<li class="list-group-item">
<field-box>
<label>sobrenome</label>
<input type="text" name="sobrenome" id="sobrenome" class="form-control" />
</field-box>
</li>
<li class="list-group-item">
<field-box>
<label>email</label>
<input type="email" name="email" id="email" class="form-control" />
</field-box>
</li>
<li class="list-group-item">
<field-box>
<label>role</label>
<select multiple="multiple" name="role.id" id="role" class="form-control option" data-classe="Role">
</select>
</field-box>
</li>
<button type="submit" id="cadastrar" class="btn btn-primary">Cadastrar</button>
<div class="alert alert-success alert-dismissible" id="yes" role="alert" style="display: none;">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
Cadastro efetuado com sucesso
</div>
<div class="alert alert-danger alert-dismissible" id="not" role="alert" style="display: none;">
<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<span class="text"></span>
</div>
</form>
the data submitted through this form is related to this class:
#Entity
#Table(name = "usuario")
public class Usuario {
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name = "login")
#Input
private String login;
#Column(name = "senha")
#Input(type = "password")
private String senha;
#Column(name = "nome")
#Input
private String nome;
#Column(name = "sobrenome")
#Input
private String sobrenome;
#Column(name = "email")
#Input(type = "email")
private String email;
#ManyToMany
#JoinTable(name="role_members", joinColumns={#JoinColumn(name="fk_user")}, inverseJoinColumns={#JoinColumn(name="fk_role")})
#LazyCollection(LazyCollectionOption.FALSE)
#Select(classe = Role.class)
private List<Role> role;
}
the submission process is handled by this jquery code:
$(document).on("submit", "form.form", function (event) {
event.preventDefault();
var $form = $( this ), url = $form.attr( "action" );
var posting = $.post( url, $(this).serialize() );
posting.done(function( data ) {
if(data == "") {
$("#yes").show();
} else {
var $temp = $('<div/>', {html:data});
$("#not").find(".text").html( $temp.remove('head').html() );
$("#not").show();
}
$("form.form").each(function(){
this.reset();
});
});
});
and by this methods in my controller, service and dao classes:
#RequestMapping(value = "insert")
#ResponseBody
public void insert(#ModelAttribute("object") E object) throws Exception {
try {
serv.insert(object);
} catch (Exception e) {
throw e;
}
}
public void insert(E object) {
dao.persist(object);
}
#Transactional
public void persist(E object) {
sessionFactory.getCurrentSession().persist(object);
}
but when I run the application and open this view in my browser, and submit this form, the data is saved in the database without the data from the <select> field. I check the browser console (in the firefox), and verify all the fields are being submitted to server, but the field role is the only one which it's not stored.
Anyone can see what's the pronlem here?
I think problem in column names you have given in #JoinTable(name="role_members", joinColumns={#JoinColumn(name="fk_user")}, inverseJoinColumns={#JoinColumn(name="fk_role")})
column name fk_user is not present in your entity class. If you want to use different name then use referencedColumnName attribute and give actual field name.
eg. We are using id from both entities then after change it will be like
#JoinTable(name="role_members", joinColumns={#JoinColumn(name="fk_user", referencedColumnName="id")}, inverseJoinColumns={#JoinColumn(name="fk_role",referencedColumnName="id")})
Hopefully it will work.

Resources