I'm using Spring and I would like to submit my agentForm with POST method but submitNewAgent isn't called on form submit. However, it works when I replace POST by GET. I've been working on it for a few days now, and I have no idea what to change. Does anyone can help me please ?
Here my files
new.html
<!DOCTYPE html>
<html lang="fr"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="index" >
<head th:replace="index :: head">
<link href="../../static/css/bootstrap.min.css" rel="stylesheet" media="screen" />
</head>
<body>
<th:block layout:fragment="body">
<h1 class="page-header"> Nouvel Agent </h1>
<form class="form" th:modelAttribute="agentForm" th:object="${agentForm}" action="/agents/ajouter-submit/" method="POST">
<div class="form-group">
<label>Prénom</label>
<div th:if="${#fields.hasErrors('prenom')}" th:errors="*{prenom}" class="text-danger">
Erreur prénom
</div>
<input type="text" th:field="*{prenom}" class="form-control" />
</div>
<div class="form-group">
<label th:for="*{nom}">Nom</label>
<div th:if="${#fields.hasErrors('nom')}" th:errors="*{nom}" class="text-danger">Erreur nom</div>
<input type="text" th:field="*{nom}" class="form-control" />
</div>
<div class="form-group">
<button class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span>
<span th:remove="tag" th:text="#{label.add}"></span>
</button>
</div>
</form>
</th:block>
</body>
</html>
AgentForm.class
public class AgentForm {
#NotNull
#Size(min=2, max=255)
private String prenom;
#NotNull
#Size(min=2, max=255)
private String nom;
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
#Override
public String toString() {
return "Agent{" +
"prenom='" + prenom + '\'' +
", nom='" + nom + '\'' +
'}';
}
}
AgentController.class link agent views and agent model.
#Controller
#RequestMapping("/agents")
public class AgentController {
private final AgentService agentService;
#Autowired
public AgentController(AgentService agentService) {
this.agentService = agentService;
}
/**
* Gets all agents
*
* #param model view
* #return template name
*/
#RequestMapping(value = {"/", "lister"}, method = RequestMethod.GET)
public String allAgents(Model model) {
List<Agent> agentList = agentService.findAll();
if (agentList != null)
model.addAttribute("agentList", agentList);
return "agents/list";
}
/**
* Displays form to add an agent
*
* #return template and attributes
*/
#RequestMapping(value = {"/", "ajouter"}, method = RequestMethod.GET)
public ModelAndView addAgentForm() {
AgentForm a = new AgentForm();
a.setNom("test");
a.setPrenom("prenom");
return new ModelAndView("agents/new", "agentForm", a);
}
/**
* Manages the form to add an agent and submit in the repository
*
* #param agentForm form
* #param result results
* #param model form the view
* #param attributes view attributes
* #return url
*/
#RequestMapping(value = {"/", "ajouter-submit"}, method = RequestMethod.POST)
public String submitNewAgent(#ModelAttribute("agentForm") #Validated AgentForm agentForm,
BindingResult result, Model model, final RedirectAttributes attributes) {
if (result.hasErrors())
return "agents/new";
agentService.saveAndFlush(AgentAdapter.adaptAgentFormToAgent(agentForm));
attributes.addFlashAttribute("css", "success");
attributes.addFlashAttribute("msg", "L'agent est correctement ajouté !");
return "redirect:/agents/lister";
}
}
I'm sorry for mixing English and French.
<!DOCTYPE html>
<html lang="fr"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.w3.org/1999/xhtml"
layout:decorator="index" >
<head th:replace="index :: head">
<link href="../../static/css/bootstrap.min.css" rel="stylesheet" media="screen" />
</head>
<body>
<th:block layout:fragment="body">
<h1 class="page-header"> Nouvel Agent </h1>
<form class="form" th:modelAttribute="agentForm" th:object="${agentForm}" th:action="#{ajouter-submit}" method="POST">
<div class="form-group">
<label>Prénom</label>
<div th:if="${#fields.hasErrors('prenom')}" th:errors="*{prenom}" class="text-danger">
Erreur prénom
</div>
<input type="text" th:field="*{prenom}" class="form-control" />
</div>
<div class="form-group">
<label th:for="*{nom}">Nom</label>
<div th:if="${#fields.hasErrors('nom')}" th:errors="*{nom}" class="text-danger">Erreur nom</div>
<input type="text" th:field="*{nom}" class="form-control" />
</div>
<div class="form-group">
<button class="btn btn-primary"><span class="glyphicon glyphicon-ok"></span>
<span th:remove="tag" th:text="#{label.add}"></span>
</button>
</div>
</form>
</th:block>
</body>
</html>
Related
I have a spring boot app and i need to Primit multi urls in security Configration but that not working I did this :
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/login/**").antMatchers("/register").antMatchers("/home");
}
and this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests().antMatchers("/login/**").permitAll()
.antMatchers("/register").permitAll()
.antMatchers("/home").permitAll()
.and().authorizeRequests().anyRequest().authenticated().and().httpBasic();
http.exceptionHandling()
.authenticationEntryPoint(
(request, response, ex) -> {
response.sendError(
HttpServletResponse.SC_UNAUTHORIZED,
ex.getMessage()
);
}
);
http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
but it's the same, no pages loaded - only login screen appears-
In first code :
In second one :
This is my view controller class :
#Controller
public class ViewController {
#Autowired
IEmployeeRepository employeeRepository;
#GetMapping("/home")
public String viewHomePage(){
return "index";
}
#GetMapping("/register")
public String showRegistrationForm(Model model) {
model.addAttribute("user", new Employee());
return "signup_form";
}
#GetMapping("/login")
public String showLoginForm() {
return "login_form";
}
#PostMapping("/process_register")
public String processRegister(Employee user) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String encodedPassword = passwordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
employeeRepository.save(user);
return "register_success";
}
#GetMapping("/addCustomer")
public String addCustomer() {
return "addcustomer";
}
#GetMapping("/addItem")
public String addItem() {
return "additem";
}
}
and this is my html :
signup_ form :
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Sign Up</title>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container text-center">
<div>
<h1>User Registration - Sign Up</h1>
</div>
<form th:action="#{/process_register}" th:object="${user}"
method="post" style="max-width: 600px; margin: 0 auto;">
<div class="m-3">
<div class="form-group row">
<label class="col-4 col-form-label">E-mail: </label>
<div class="col-8">
<input type="email" th:field="*{email}" class="form-control" required />
</div>
</div>
<label class="col-4 col-form-label">Serial Number : </label>
<div class="col-8">
<input type="email" th:field="*{serialNumber}" class="form-control" required />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Password: </label>
<div class="col-8">
<input type="password" th:field="*{password}" class="form-control"
required minlength="4" maxlength="10"/>
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">First Name: </label>
<div class="col-8">
<input type="text" th:field="*{firstName}" class="form-control"
required minlength="2" maxlength="20"/>
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Last Name: </label>
<div class="col-8">
<input type="text" th:field="*{lastName}" class="form-control"
required minlength="2" maxlength="20" />
</div>
</div>
<div class="form-group row">
<label class="col-4 col-form-label">Country: </label>
<div class="col-8">
<input type="text" th:field="*{country}" class="form-control"
required minlength="2" maxlength="20" />
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">Sign Up</button>
</div>
</form>
</div>
</body>
</html>
The index html :
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Welcome</title>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
<script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
<script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container text-center">
<h1>Welcome</h1>
<h3><a th:href="/#{/users}">List of Users</a></h3>
<h3><a th:href="/#{/register}">Register</a></h3>
<h3><a th:href="/#{/login}">Login</a></h3>
</div>
</body>
</html>
and this is Employee model :
#Entity
#Table(name = "employee")
public class Employee implements UserDetails {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private int id;
#Column(name = "serial_number")
private long serialNumber;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "role_id")
private Role role;
private String email;
private String mobileNumber;
private String country;
private String password;
private boolean isDeleted;
#OneToMany
private Set<Invoice> invoices;
#OneToMany
private Set<InvoiceHistory> invoiceHistories;
public Employee(){}
public Employee(long serialNumber, String firstName, String lastName, Role role, String email, String mobileNumber,String country,String password){
super();
this.serialNumber = serialNumber;
this.firstName = firstName;
this.lastName = lastName;
this.role= role;
this.email = email;
this.mobileNumber = mobileNumber;
this.country = country;
this.password = password;
this.isDeleted = false;
}
The first one you are using ignoring lol.
The second one it's not Spring Security problem. This is Thymeleaf error, check your thymeleaf parsing.
My resister page works fine, it takes the input and pushes to data base when "register" is clicked. However, when I click to go to a "list an item" page, which similarly takes input to be pushed to a table in a database when "list item" is clicked, it comes up with "Request Method 'POST' not supported". So the "list an item" page doesn't appear when clicked from the main logged-in menu page.
Part of the controller class here:
#GetMapping("/register")
public String goToRegisterPage(Model model) {
User user = new User();
model.addAttribute("user", user);
return "register_page";
}
#GetMapping("/go_to_create_item_page")
public String goToCreateItemPage(Model model) {
FreeItem freeItem = new FreeItem();
model.addAttribute("freeItem", freeItem);
return "create_item_page";
}
Part of the html file here that offers to go to the create_item_page:
<div>
<form th:action="#{/update_user_page}" method="post">
<input type="submit" value="Update account" />
</form>
</div>
<div>
<form th:action="#{/go_to_create_item_page}" method="post">
<input type="submit" value="List an Item" />
</form>
</div>
The create_item_page:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Create Item</title>
<link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css" />
</head>
<body>
<div class="container text-center">
<div>
<h1>Create an Item to list publicly</h1>
</div>
<form th:action="#{/process_created_item}" method="post"
style="max-width: 600px; margin: 0 auto;"
th:object="${freeItem}">
<div class="m-3">
<div class="form-group row">
<label class="col-form-label col-4">Item Name</label>
<div class="col-8">
<input type="text" class="form-control" th:field="*{itemName}" required
minlength="2" maxlength="20" />
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-4">Item Description</label>
<div class="col-8">
<input type="text" class="form-control"
th:field="*{itemDescription}" required
minlength="6" maxlength="10" />
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-4">Quantity Of Item</label>
<div class="col-8">
<input type="text" class="form-control" th:field="*{quantityOfItem}" required
minlength="2" maxlength="20" />
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-4">General Item Location</label>
<div class="col-8">
<input type="text" class="form-control" th:field="*{itemLocation}"
required minlength="2" maxlength="20" />
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-4">E-mail for contact</label>
<div class="col-8">
<input type="email" class="form-control" th:field="*{email}"
required />
</div>
</div>
<div>
<button type="submit" class="btn btn-primary">List Item</button>
</div>
</div>
</form>
</div>
</body>
</html>
And the FreeItem class that specifies the objects being pushed to the database.
package com.marinelli.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name= "free_items")
public class FreeItem {
public FreeItem(String itemName, String itemDescription, String quantityOfItem, String itemLocation, String email) {
super();
this.itemName = itemName;
this.itemDescription = itemDescription;
this.quantityOfItem = quantityOfItem;
this.itemLocation = itemLocation;
this.email = email;
}
public FreeItem() {
}
#Id
#Column(nullable = false, unique = true, length = 64)
private String itemName;
#Column(nullable = false, length = 64)
private String itemDescription;
#Column(nullable = false, length = 25)
private String quantityOfItem;
#Column(nullable = false, length = 25)
private String itemLocation;
#Column(nullable = false, unique = true, length = 45)
private String email;
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemDescription() {
return itemDescription;
}
public void setItemDescription(String itemDescription) {
this.itemDescription = itemDescription;
}
public String getQuantityOfItem() {
return quantityOfItem;
}
public void setQuantityOfItem(String quantityOfItem) {
this.quantityOfItem = quantityOfItem;
}
public String getItemLocation() {
return itemLocation;
}
public void setItemLocation(String itemLocation) {
this.itemLocation = itemLocation;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Override
public String toString() {
return "FreeItem [itemName=" + itemName + ", itemDescription=" + itemDescription + ", quantityOfItem="
+ quantityOfItem + ", itemLocation=" + itemLocation + ", email=" + email + "]";
}
}
you need to create go_to_create_item_page and update_user_page as #Postmapping("....")
#Postmapping("/update_user_page")
public String goToUpdateUserPage(Model model) {
...
...
...
}
#Postmapping("/go_to_create_item_page")
public String goToCreateItemPage(Model model) {
...
...
...
}
The error clearly stated that you are using the incorrect method for that provided endpoint.
In your case, /go_to_create_item_page defined as GET, your form declared method = post. Either changing them to both use POST or GET should resolve the problem (In terms of API design, it should be GET, as you are getting resources from the server rather than creating / updating).
So here is my Controller. First of all, here I have both request methods GET and POST but for some strange reason the GetMapping("/journeys") is not being recognized.
#Controller
#GetMapping("/journeys")
String journeys(Model model , #Valid JourneyForm form) {
model.addAttribute("journeys", journeys.findAll()) ;
model.addAttribute("form", form);
return "journeys" ;}
#GetMapping("/jounreyCreate")
String createJourney(Model model , JourneyForm form){
model.addAttribute("form", form) ;
return "journeyCreate" ;
}
#PostMapping("/journeyCreate")
String createJourney(Model model ,Errors errors,#Valid #ModelAttribute("form") JourneyForm form ) {
if (errors.hasErrors()) {
return journeys(model , form);
}
journeys.save( form.createJourney() ) ;
return "redirect:/journeys";
}
and here is the JourneyForm Class
public class JourneyForm {
private String name;
public JourneyForm(String name) {
this.name = name ;
}
public String getName() {
return name;
}
public Journey createJourney() {
return new Journey(getName());
}
}
and for the last part the journey.html and journeyCreate.html
<body>
<h2 th:text="#{journeys.title}">Reise</h2>
<a href="/journeyCreate">
<button class="ui button">Journey erstellen</button>
</a>
<a href="/journeyEdit">
<button class="ui button">Reise bearbeiten</button>
</a>
<div th:each="journey : ${journeys}">
<p th:text="'Reise: '+${journey.name}">Reise</p>
</div>
and journeyCreate.html
<a href="/journeys">
<button class="ui button">Zurück zur Reise</button>
</a>
<form role="form" class="ui form" id="form" th:object="${form}" th:method="post" th:action="#{/journeyCreate}">
<div class="field">
<label for="journeyName">Name</label>
<input id="journeyName" name="journeyName" type="text" th:field="*{name}" th:errorclass="is-invalid" required="required"/><br/>
<div th:if="${#fields.hasErrors('name')}" class="invalid-feedback">Please provide a name.</div>
</div>
<input type="submit" value="Submit">
</form>
it is really frustrating and I can't get my hand on the cause
Your help will be appreciated, thank you.
I am writing form that lets user to change his password. Instead of passing User object to form, I am passing 3 empty Strings. Everything is okay, but when I am passing Submit, Strings returns as empty. Is there any way to get String from forms in Spring without packaging them into objects like changePasswordForm with 3 String fields?
My code:
Change password view:
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="${currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="${newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="${newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
User controller:
package io.gromo13.personalBlog.controller;
import io.gromo13.personalBlog.service.RoleService;
import io.gromo13.personalBlog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import io.gromo13.personalBlog.model.User;
import javax.validation.Valid;
#Controller
#RequestMapping("/user")
#SessionAttributes("user")
public class UserController {
#Autowired
UserService userService;
#Autowired
RoleService roleService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setRoleService(RoleService roleService) {
this.roleService = roleService;
}
#GetMapping("/{id}")
public String profile(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
return "/user/profile";
}
#GetMapping("/register")
public String register(Model model) {
model.addAttribute("roles", roleService.getAll());
model.addAttribute("user", new User());
return "/user/register";
}
#PostMapping("/register")
public String registerSubmit(#Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/register";
userService.add(user);
return "redirect:/admin/users";
}
#GetMapping("/edit/{id}")
public String edit(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
model.addAttribute("password", "");
return "/user/edit";
}
#PostMapping("/edit/{id}")
public String editSubmit(#ModelAttribute("user") #Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/edit";
userService.edit(user);
return "redirect:/admin/users";
}
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", "");
model.addAttribute("newPassword", "");
model.addAttribute("newPasswordConfirmation", "");
return "/user/changePassword";
}
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#ModelAttribute("currentPassword") String currentPassword,
#ModelAttribute("newPassword") String newPassword,
#ModelAttribute("newPasswordConfirmation") String newPasswordConfirmation,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/changePassword";
User user = userService.get(id);
if (newPassword.equals(newPasswordConfirmation) && user.getPassword().equals(currentPassword)) {
user.setPassword(newPassword);
userService.edit(user);
}
return "redirect:/admin/users";
}
#GetMapping("/delete/{id}")
public String delete(#PathVariable Long id) {
userService.delete(id);
return "redirect:/admin/users";
}
}
Actually my whole page is working fine, I just cannot read single Strings passed to forms without wrapping to objects.
Every tutorial about forms in Spring I found is passing object like xForm or User to view and read them. It works for me too, but I do not see sense in creating special object just for single form.
change th:field to name tag
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" name="currentPassword" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" name="newPassword" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" name="newPasswordConfirmation" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
remove this from controller
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", ""); //remove
model.addAttribute("newPassword", ""); //remove
model.addAttribute("newPasswordConfirmation", ""); //remove
return "/user/changePassword";
}
and here change ModelAttribute to RequestParam Annotation
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#RequestParam("currentPassword") String currentPassword,
#RequestParam("newPassword") String newPassword,
#RequestParam("newPasswordConfirmation") String newPasswordConfirmation) {
this sentence bindingResult not work because this validate a POJO using validations annotations
//if (bindingResult.hasErrors())
// return "/user/changePassword";
for this case the best way is create a new POJO with those fields and then validate them.
if you want to use the validation you need to create a POJO and add the constraints.
1)
public class ChangePass {
#Size(min = 8,max = 13, message = "error current password between {min} to {max}")
private String currentPassword;
#Size(min = 8,max = 13,message = "error new password between {min} to {max}")
private String newPassword;
//validate later
private String newPasswordConfirmation;
}
2)
then you need to add a instance of this POJO in the view.
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("userPass", new ChangePass()); // adding model
return "/user/changePassword";
}
3)
in your form you need to fix 2 things add
th:object="${userPass}" and add th:field="*{currentPassword}" not th:field="${currenctPassword}" the difference is " * "
<form th:action="#{/user/changePassword/} + ${user.id}" method="post" th:object="${userPass}">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="*{currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="*{newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="*{newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
4)
and the Post Method should be...
#PostMapping("/changePassword/{id}")
public String changePassword(#PathVariable Long id,
#ModelAttribute("userPass"),
#Valid ChangePass change,
BindingResult errors){
if(errors.hasErrors()){
return "/user/changePassword";
}
//your next code
I have a strange error to my code. I am writing code for a eshop.
I have written code for validation when admin add products where the name field is empty. When I click the submit button the addProduct page reload with the message error that I defined.
With similar way I write code for validation when admin edit a product. I try to edit a product with an empty name that violates the NotEmpty that I have defined at the Product.java.
AddProduct at HomeController
#RequestMapping(value = "/admin/productInventory/addProduct", method = RequestMethod.POST)
public String addProductPost(#Valid #ModelAttribute("product") Product product, BindingResult result,
HttpServletRequest request) {
if (result.hasErrors()) {
return "addProduct";
}
addProduct.jsp
<div class="form-group">
<label for="name">Name</label>
<form:errors path="productName" cssStyle="color: #ff0000;" />
<form:input path="productName" id="name" class="form-Control" />
</div>
EditProduct at HomeController
#RequestMapping(value = "/admin/productInventory/editProduct", method = RequestMethod.POST)
public String editProduct(#Valid #ModelAttribute("product") Product product, Model model, BindingResult result,
HttpServletRequest request) {
if (result.hasErrors()) {
return "editProduct";
}
editProduct.jsp
<div class="form-group">
<label for="name">Name</label>
<form:errors path="productName" cssStyle="color: #ff0000;" />
<form:input path="productName" id="name" class="form-Control"
value="${product.productName}" />
</div>
product.java
#Column(name="productName")
#NotEmpty (message = "The product name must not be null.")
private String productName;
When I try to click the submit button on editProduct (with an empty name) I take:
HTTP Status 400 -
type Status report
message
description The request sent by the client was syntactically incorrect.
Apache Tomcat/9.0.0.M17
What's going wrong?
EDIT
editProduct.jsp
<%#taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%#include file="/WEB-INF/views/template/header.jsp"%>
<div class="container-wrapper">
<div class="container">
<div class="page-header">
<h1>Edit Product</h1>
<p class="lead">Please update the product information here:</p>
</div>
<form:form
action="${pageContext.request.contextPath}/admin/productInventory/editProduct"
method="post" commandName="product" enctype="multipart/form-data">
<form:hidden path="productId" value="${product.productId}" />
<div class="form-group">
<label for="name">Name</label>
<form:errors path="productName" cssStyle="color: #ff0000;" />
<form:input path="productName" id="name" class="form-Control"
value="${product.productName}" />
</div>
<div class="form-group">
<label for="category">Category</label> <label
class="checkbox-inline"><form:radiobutton
path="productCategory" id="category" value="instrument" />Instrument</label>
<label class="checkbox-inline"><form:radiobutton
path="productCategory" id="category" value="record" />Record</label> <label
class="checkbox-inline"><form:radiobutton
path="productCategory" id="category" value="accessory" />Accessory</label>
</div>
<div class="form-group">
<label for="description">Description</label>
<form:textarea path="productDescription" id="description"
class="form-Control" value="${product.productDescription}" />
</div>
<div class="form-group">
<label for="price">Price</label>
<%-- <form:errors path="productPrice" cssStyle="color: #ff0000;" /> --%>
<form:input path="productPrice" id="price" class="form-Control"
value="${product.productPrice}" />
</div>
<div class="form-group">
<label for="condition">Condition</label> <label
class="checkbox-inline"><form:radiobutton
path="productCondition" id="condition" value="new" />New</label> <label
class="checkbox-inline"><form:radiobutton
path="productCondition" id="condition" value="used" />Used</label>
</div>
<div class="form-group">
<label for="status">Status</label> <label class="checkbox-inline"><form:radiobutton
path="productStatus" id="status" value="active" />Active</label> <label
class="checkbox-inline"><form:radiobutton
path="productStatus" id="status" value="inactive" />Inactive</label>
</div>
<div class="form-group">
<label for="unitInStock">Unit In Stock</label>
<%-- <form:errors path="unitInStock" cssStyle="color: #ff0000;" /> --%>
<form:input path="unitInStock" id="unitInStock" class="form-Control"
value="${product.unitInStock}" />
</div>
<div class="form-group">
<label for="manufacturer">Manufacturer</label>
<form:input path="productManufacture" id="manufacturer"
class="form-Control" value="${product.productManufacture}" />
</div>
<div class="form-group">
<label class="control-label" for="productImage">Upload
Picture</label>
<form:input id="productImage" path="productImage" type="file"
class="form:input-large" />
</div>
<br>
<br>
<input type="submit" value="submit" class="btn btn-default">
<a href="<c:url value="/admin/productInventory" />"
class="btn btn-default">Cancel</a>
</form:form>
</div>
</div>
<%#include file="/WEB-INF/views/template/footer.jsp"%>
header.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>My Music Store</title>
<!-- Bootstrap core CSS -->
<link href="<c:url value="/resources/css/bootstrap.min.css" />"
rel="stylesheet">
<!-- Carousel core CSS -->
<link href="<c:url value="/resources/css/carousel.css" />"
rel="stylesheet">
<!-- My Main CSS style-->
<link href="<c:url value="/resources/css/main.css" />" rel="stylesheet">
</head>
<!-- NAVBAR
================================================== -->
<body>
<div class="navbar-wrapper">
<div class="container">
<nav class="navbar navbar-inverse navbar-static-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#navbar" aria-expanded="false"
aria-controls="navbar">
<span class="sr-only">Toggle navigation</span> <span
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">My Music Store</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>Home</li>
<li>Products</li>
<li>Contact</li>
</ul>
<ul class="nav navbar-nav pull-right">
<li>Admin</li>
</ul>
</div>
</div>
</nav>
</div>
</div>
EDIT AGAIN
Product
package com.entities;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.Min;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.web.multipart.MultipartFile;
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="productId")
private String productId;
#Column(name="productName")
#NotEmpty (message = "The product name must not be null.")
private String productName;
#Column(name="productCategory")
private String productCategory;
#Column(name="productDescription")
private String productDescription;
#Min (value = 0, message = "The product price must no be less than zero.")
#Column(name="productPrice")
private double productPrice;
#Column(name="productCondition")
private String productCondition;
#Column(name="productStatus")
private String productStatus;
#Min (value = 0, message = "The product unit must no be less than zero.")
#Column(name="unitInStock")
private int unitInStock;
#Column(name="productManufacture")
private String productManufacture;
#Transient /*do not store to database*/
private MultipartFile productImage;
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductCategory() {
return productCategory;
}
public void setProductCategory(String productCategory) {
this.productCategory = productCategory;
}
public String getProductDescription() {
return productDescription;
}
public void setProductDescription(String productDescription) {
this.productDescription = productDescription;
}
public double getProductPrice() {
return productPrice;
}
public void setProductPrice(double productPrice) {
this.productPrice = productPrice;
}
public String getProductCondition() {
return productCondition;
}
public void setProductCondition(String productCondition) {
this.productCondition = productCondition;
}
public String getProductStatus() {
return productStatus;
}
public void setProductStatus(String productStatus) {
this.productStatus = productStatus;
}
public int getUnitInStock() {
return unitInStock;
}
public void setUnitInStock(int unitInStock) {
this.unitInStock = unitInStock;
}
public String getProductManufacture() {
return productManufacture;
}
public void setProductManufacture(String productManufacture) {
this.productManufacture = productManufacture;
}
public MultipartFile getProductImage() {
return productImage;
}
public void setProductImage(MultipartFile productImage) {
this.productImage = productImage;
}
}