Thymeleaf errors are not showing on page but validation is fine - spring

Controller:
#PostMapping("/saveExpense/{walletId}")
public String saveExpense(#PathVariable(value = "walletId") long walletId,
#ModelAttribute("wallets") #Valid Transaction transaction, BindingResult result, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
Wallet wallet = walletService.getWalletById(walletId);
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
model.addAttribute("transaction", transaction);
return "redirect:/api/transaction/showNewTransactionForm/" + walletId;
}
transaction.setWallet(wallet);
transactionService.saveExpense(transaction, walletId, userId);
return "redirect:/api/wallet/userWallet/balance/" + userId;
}
This is form inside Thymeleaf:
<form action="#" id="Expense" class="hidden" th:action="#{/api/transaction/saveExpense/{walletId} (walletId=${id})}"
th:object="${transaction}" method="POST">
<input type="text" th:field="*{amount}" placeholder="Enter amount" class="form-control mb-4 col-4">
<p th:if="${#fields.hasErrors('amount')}" th:class="${#fields.hasErrors('amount')}? error">
Invalid Age</p>
<input type="text" th:field="*{note}" placeholder="Enter note" class="form-control mb-4 col-4">
<input type="date" th:field="*{date}" class="form-control mb-4 col-4">
<select th:field="${transaction.expenseCategories}">
<option value="0">Select expense category</option>
<option
th:each="expenseCategories : ${expenseCategories}"
th:value="${expenseCategories}"
th:text="${expenseCategories.displayName}"
></option>
</select>
<button type="submit" class="btn btn-info col-2"> Save Wallet</button>
</form>
Here is the part of field that I want to display error:
<input type="text" th:field="*{amount}" placeholder="Enter amount" class="form-control mb-4 col-4">
<p th:if="${#fields.hasErrors('amount')}" th:class="${#fields.hasErrors('amount')}? error">
Invalid Age</p>
And inside model:
#Min(value = 0, message = "Please, insert a positive amount")
private double amount;
So for example, if I try to set amount -1 and after I submit form, that data is not saved in database so that is fine, but I cant see errors on page, I just get redirected to same page but no errors are showing.
Just to mention, I already tried to find something useful here on SO but nothing worked so far

Related

Form is not saved because it has errors, but errors are not displayed

I have a SignUp form for user, also I have a validation for fields, I'll provide all of that. So, when user insert for example on field username > s but that field need to have more then 3 characters, program should show error and not save that data into table. What's happening? Application process the error, I mean form is not submitted when I made a error on purpose, but error is not showing on HTML, not on stack trace. Page is just returned but error message are not showing, good thing is just that form is not saved if there is error so that work, problem is just message not appearing.
I have a SignUp form, and for example I have this validation on username and firstName:
#NotEmpty
#Size(min = 3, max = 20, message = "Username not valid")
private String username;
#NotEmpty(message = "Please, insert a first name")
private String firstName;
This is how I display form, its login and register on same page, that is why I have two model attributes:
#GetMapping("/loginAndRegisterForm")
public String showLoginForm(Model model) {
// create model object to store form data
LoginRequest loginRequest = new LoginRequest();
SignupRequest signupRequest = new SignupRequest();
model.addAttribute("login", loginRequest);
model.addAttribute("user", signupRequest);
return "login_and_registration";
}
This is SignUp controller, with result.hasErrors() inside it:
#PostMapping("/signup")
#Transactional
public String signup(#ModelAttribute("signup") #Valid SignupRequest signupRequest, BindingResult result, Model model) throws Exception {
boolean thereAreErrors = result.hasErrors();
if (thereAreErrors) {
LoginRequest loginRequest = new LoginRequest();
model.addAttribute("user", signupRequest);
model.addAttribute("signup", signupRequest);
model.addAttribute("login", loginRequest);
return "login_and_registration";
}
User user = new User(signupRequest.getUsername(), signupRequest.getFirstName(), signupRequest.getLastName(), signupRequest.getEmail(), encoder.encode(signupRequest.getPassword()));
model.addAttribute("signup", signupRequest);
userRepository.save(user);
return "redirect:/api/auth/loginAndRegisterForm";
}
And this is Thymeleaf:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Security Tutorial</title>
<link rel="stylesheet" type="text/css" th:href="#{/css/loginAndRegistration.css}"/>
</head>
<body>
<div class="main">
<input type="checkbox" id="chk" aria-hidden="true">
<div class="signup">
<form
method="post"
role="form"
th:action="#{/api/auth/signup}"
th:object="${user}">
<label for="chk" aria-hidden="true">Sign up</label>
<input
class="form-control"
id="usernameSignUp"
name="username"
placeholder="Enter username"
th:field="*{username}"
type="text"/>
<p th:errors="*{username}" class="text-danger"
th:if="${#fields.hasErrors('username')}"></p>
<input
class="form-control"
id="firstName"
name="firstName"
placeholder="Enter first name"
th:field="*{firstName}"
type="text"/>
<p th:errors="*{firstName}" class="text-danger"
th:if="${#fields.hasErrors('firstName')}"></p>
<input
class="form-control"
id="lastName"
name="lastName"
placeholder="Enter lastName"
th:field="*{lastName}"
type="text"/>
<p th:errors="*{firstName}" class="text-danger"
th:if="${#fields.hasErrors('firstName')}"></p>
<input
class="form-control"
id="email"
name="email"
placeholder="Enter email"
th:field="*{email}"
type="email"/>
<p th:errors="*{email}" class="text-danger"
th:if="${#fields.hasErrors('email')}"></p>
<input
class="form-control"
id="passwordSignUp"
name="password"
placeholder="Enter password"
th:field="*{password}"
type="password"/>
<p th:errors="*{password}" class="text-danger"
th:if="${#fields.hasErrors('password')}"></p>
<button>Sign up</button>
</form>
</div>
<div class="login">
<form
method="post"
role="form"
th:action="#{/api/auth/login}"
th:object="${login}">
<label for="chk" aria-hidden="true">Login</label>
<input
class="form-control"
id="usernameLogin"
name="username"
placeholder="Enter username"
th:field="*{username}"
type="text"/>
<p th:errors="*{username}" class="text-danger"
th:if="${#fields.hasErrors('username')}"></p>
<input
class="form-control"
id="passwordLogin"
name="password"
placeholder="Enter password"
th:field="*{password}"
type="password"/>
<p th:errors="*{password}" class="text-danger"
th:if="${#fields.hasErrors('password')}"></p>
<button>Login</button>
</form>
</div>
</div>
</body>
</html>

Spring Required request part 'file' is not present

I'm trying to upload an image with a form, it's going to be the profile picture, but I get the error:
Required request part 'file' is not present
I'm really new with spring, so I don't know what's wrong here's part of the code:
This is the form
<form th:action="#{/form}" th:object="${cliente}" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>Nombre</label>
<input class="form-control" type="text" th:field="*{nombre}" placeholder="Nombre"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('nombre')}" th:errors="*{nombre}"></small>
</div>
<div class="form-group">
<label>Apellido</label>
<input class="form-control" type="text" th:field="*{apellido}" placeholder="Apellido"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('apellido')}" th:errors="*{apellido}"></small>
</div>
<div class="form-group">
<label>Email</label>
<input class="form-control" type="text" th:field="*{email}" placeholder="correo#ejemplo.com"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></small>
</div>
<div class="form-group">
<label>Fecha</label>
<input class="form-control" type="text" th:field="*{createAt}" placeholder="DD/MM/YYYY"/>
<small class="form-text text-danger" th:if="${#fields.hasErrors('createAt')}" th:errors="*{createAt}"></small>
</div>
<div class="form-group">
<label>Imagen</label>
<input type="file" name="file" class="form-control" th:field="*{foto}">
</div>
<div class="form-group">
<input class="btn btn-primary" type="submit" value="Guardar Cambios" />
</div>
<input type="hidden" th:field="*{id}" />
</form>
This is the controller function
#RequestMapping(value="/form", method=RequestMethod.POST)
public String guardar(#Valid Cliente cliente, BindingResult result,
#RequestParam("file") MultipartFile foto, RedirectAttributes flash) {
String mensaje;
if(result.hasErrors()) {
return "form";
}
if(!foto.isEmpty()) {
Path directorioRecursos = Paths.get("src//main//resources//static/uploads");
String pathRoot = directorioRecursos.toFile().getAbsolutePath();
try {
byte[] bytes = foto.getBytes();
Path rutaCompleta = Paths.get(pathRoot + "//" + foto.getOriginalFilename());
Files.write(rutaCompleta, bytes);
flash.addFlashAttribute("info", "Foto subida correctamente");
cliente.setFoto(foto.getOriginalFilename());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(cliente.getId() != null) {
mensaje = "Cliente actualizado correctamente";
}
else {
mensaje = "Cliente creado correctamente";
}
clienteservice.save(cliente);
flash.addFlashAttribute("success", mensaje);
return "redirect:listar";
}
This is my application properties
spring.http.multipart.file-size=10MB
spring.http.multipart.max-request-size=10MB
spring.http.multipart.enabled=true
Can you see what's wrong?
you're attaching a file to a string field with the th:field="*{foto}" ,
remove the th:field part in the input , should be like this:
<input type="file" name="file" class="form-control" />

Vue.js Asp.NET core Form validation

I am currently learning vuejs with asp .net core right now.
I am doing some form validation and adding some error messages.
The error messages are from the Server side here is my sample code:
[HttpPost]
public async Task<IActionResult> AddUser([FromBody] UserModel user)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (_context.Users.Any(u => u.UserName == user.UserName))
{
ModelState.AddModelError("UserName", "Username is already in used");
return BadRequest(ModelState);
}
try
{
var userDto = new User
{
FirstName = user.FirstName,
LastName = user.LastName,
Password = user.Password,
UserName = user.UserName
};
_context.Users.Add(userDto);
await _context.SaveChangesAsync();
}
catch(Exception e)
{
ModelState.AddModelError("Saving Error", string.Format("Error in saving user. \nDetails:\n {0}", e.Message));
return BadRequest(ModelState);
}
return Ok();
}
And in the view:
<form v-on:submit.prevent="SaveUser()">
<div class="form-group">
<label for="userName">User Name</label>
<input class="form-control" type="text" id="userName" placeholder="Username" v-model="userName" required :disabled="isEditMode" />
</div>
<div class="form-group">
<label for="userName">First Name</label>
<input class="form-control" type="text" id="firstName" placeholder="First Name" v-model="firstName" required />
</div>
<div class="form-group">
<label for="userName">Last Name</label>
<input class="form-control" type="text" id="lastName" placeholder="Lastname" v-model="lastName" required />
</div>
<div v-if="!isEditMode">
<div class="form-group">
<label for="userName">Password</label>
<input class="form-control" type="password" id="password" placeholder="Password" v-model="password" required />
</div>
</div>
<!--TODO: Distribute to each control-->
<div v-if="hasError">
<ul v-for="error in errors">
<li style="color: red;" v-for="detail in error">{{detail}}</li>
</ul>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<button type="button" #click="backToList()" class="btn btn-danger">Cancel</button>
</form>
Basically I am doing the validations from the server-side.
Currently the error messages are displayed below the controls
And I need to distribute all the error message inline with the inputs.
Can you help me with this?
Thanks in advance.

Springboot - java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute [duplicate]

This question already has answers here:
What causes "java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'command' available as request attribute"?
(7 answers)
Closed 5 years ago.
I get the following error:
java.lang.IllegalStateException: Neither BindingResult nor plain target object
for bean name 'user' available as request attribute
When I try to call this method:
#RequestMapping(value="/invite", method = RequestMethod.GET)
public ModelAndView showInvitePage(ModelAndView modelAndView,#ModelAttribute("user") User user){
return modelAndView;
}
this is the thymeleaf page:
<div class="container">
<div class="wrapper">
<form class="form-activate" th:action="#{/invite}" method="post" th:object="${user}">
<h2 class="form-activate-heading">Nodig een student uit</h2>
<p>Vul hier het e-mailadres in van de student die je wil uitnodigen:</p>
<div class="form-group">
<input type="text" th:field="*{username}" class="form-control input-lg"
placeholder="Username" tabindex="1"/>
</div>
<div class="form-group">
<input type="text" th:field="*{email}" class="form-control input-lg"
placeholder="Username" tabindex="2"/>
</div>
<div class="row">
<div class="col-xs-6 col-sm-6 col-md-6">
<input type="submit" class="btn btn-secondary" value="Invite"/>
</div>
</div>
</form>
</div>
It's odd because I have another method which is almost a copy of this one and it works perfectly fine here:
#RequestMapping(value="/register", method = RequestMethod.GET)
public ModelAndView showRegistrationPage(ModelAndView modelAndView, #ModelAttribute User user){
return modelAndView;
}
and the thymeleaf page:
<div class="wrapper">
<form class="form-signin" th:action="#{/register}" method="post" th:object="${user}">
<h2 class="form-signin-heading">Registratie</h2>
<div class="form-group">
<input type="text" th:field="*{username}" class="form-control input-lg"
placeholder="Username" tabindex="1"/>
</div>
<div class="form-group">
<input type="text" th:field="*{email}" class="form-control input-lg"
placeholder="Email" tabindex="2"/>
</div>
<div class="form-group">
<input type="password" th:field="*{encryptedPassword}" id="password" class="form-control input-lg"
placeholder="Password" tabindex="3"/>
</div>
<div class="form-group">
<input type="password" name="password_confirmation" id="password_confirmation"
class="form-control input-lg" placeholder="Confirm Password" tabindex="4"/>
</div>
The only thing I might think of is that when you call the invite method, a user is already logged in and is doing the actual inviting. When registering, no user is logged in yet.
EDIT:
I removed the thymeleaf th:field from the input fields and used the classic way and it works fine now.
<div class="form-group">
<input type="text" name="username" id="username" class="form-control input-lg"
placeholder="Username" tabindex="2"/>
</div>
<div class="form-group">
<input type="text" name="email" id="email" class="form-control input-lg"
placeholder="Email" tabindex="2"/>
</div>
You are getting this exception because there is no user object to which Spring can bind. So add one to the model in your GET method:
#GetMapping("/invite") //use shorthand
public String showInvitePage(Model model) {
model.addAttribute("user", new User()); //or however you are creating them
return "theFormNameWithoutTheExtension";
}
Then your POST would have the processing:
#PostMapping("/register")
public String showRegistrationPage(#ModelAttribute("user") User user) {
//do your processing
return "someConfirmationPage";
}

Spring get data from html select

I'm using Spring MVC to build website.
I have a simple form in HTML:
<form action="#" th:action="#{/new_product}" th:object="${webProduct}" method="post">
<p>Name: <input type="text" th:field="*{name}" /></p>
<p>Des: <input type="text" th:field="*{description}" /></p>
<p>Price: <input type="text" th:field="*{price}" /></p>
<p>Category: </p>
<select>
<th:forEach th:each="category : ${categories}">
<option th:text="${category.name}" th:value="${category.category_id}"></option>
</th:forEach>
</select>
<p><input type="submit" value="Save" /></p>
</form>
When user click button I call the method:
#RequestMapping(value = "/new_product", method = RequestMethod.POST)
public String setNewProduct(#Valid WebProduct product, Model model){
//productService.add(product, "test");
System.out.println("Value: " + product.getName());
System.out.println("Value: " + product.getDescription());
System.out.println("Value: " + product.getPrice());
System.out.println("Value: " + product.getCategoryId());
return "add_ok";
}
Name, description, price are showing but categoryId not. Where is the problem?

Resources