I try to make a register page for my application and when I press submit button this error appears:
Exception evaluating SpringEL expression: "#fields.hasErrors('firstName')"
From what I understand, Thymleaf uses POJO's getters for validation and this means that firstName attribute couldn't be found. For registration I use a DTO for user entity, a DTO only for registration. If i use user entity this error never appears. What am I doing wrong?
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Registration Form</title>
<link rel="stylesheet" type="text/css" th:href="#{/css/registration.css}"/>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<form autocomplete="on" action="register.html" th:action="#{/user/register}"
th:object="${user}" method="post" class="form-horizontal"
role="form">
<h2>Registration Form</h2>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('firstName')}" th:errors="*{firstName}"
class="validation-message"></label>
<input type="text" th:field="*{firstName}" placeholder="Name"
class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('lastName')}" th:errors="*{lastName}"
class="validation-message"></label>
<input type="text" th:field="*{lastName}"
placeholder="Last Name" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('username')}" th:errors="*{username}"
class="validation-message"></label>
<input type="text" th:field="*{username}"
placeholder="Username" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="text" th:field="*{emailAddress}" placeholder="Email"
class="form-control"/> <label
th:if="${#fields.hasErrors('emailAddress')}" th:errors="*{emailAddress}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<label th:if="${#fields.hasErrors('phoneNumber')}" th:errors="*{phoneNumber}"
class="validation-message"></label>
<input type="text" th:field="*{phoneNumber}"
placeholder="Phone Number" class="form-control"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="password" th:field="*{password}"
placeholder="Password" class="form-control"/> <label
th:if="${#fields.hasErrors('password')}" th:errors="*{password}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<input type="password" th:field="*{confirmPassword}"
placeholder="Confirm Password" class="form-control"/> <label
th:if="${#fields.hasErrors('confirmPassword')}" th:errors="*{confirmPassword}"
class="validation-message"></label>
</div>
</div>
<div class="form-group">
<div class="col-sm-9">
<button type="submit" class="btn btn-primary btn-block">Register User</button>
</div>
</div>
<h2><span class="text-success" th:utext="${successMessage}"></span></h2>
</form>
</div>
</div>
</div>
</body>
</html>
RegisterUserDto
#PasswordMatches
public class RegisterUserDto {
private Long id;
#NotNull(message = "This field can't be null")
#NotEmpty(message = "This field can't be empty")
private String firstName;
#NotNull(message = "This field can't be null")
#NotEmpty(message = "This field can't be empty")
private String lastName;
#NotNull(message = "This field can't be null")
#NotEmpty(message = "This field can't be empty")
private String username;
#NotNull(message = "This field can't be null")
#NotEmpty(message = "This field can't be empty")
#ValidEmail
private String emailAddress;
#NotNull(message = "This field can't be null")
#NotEmpty(message = "This field can't be empty")
#ValidPhoneNumber
private String phoneNumber;
#ValidPassword
private String password;
private String confirmPassword;
//getters and setters
Controller
#GetMapping("/register")
public ModelAndView registration(){
ModelAndView modelAndView = new ModelAndView();
RegisterUserDto user = new RegisterUserDto();
modelAndView.addObject("user", user);
modelAndView.setViewName("register");
return modelAndView;
}
#PostMapping("/register")
public ModelAndView createNewUser(#Valid RegisterUserDto user,
BindingResult bindingResult) {
ModelAndView modelAndView = new ModelAndView();
User userExists = userService.findUserByEmail(user.getEmailAddress());
if (userExists != null) {
bindingResult
.rejectValue("emailAddress", "error.user",
"There is already a user registered with the email provided");
}
if (bindingResult.hasErrors()) {
modelAndView.setViewName("register");
} else {
userService.createUser(user);
modelAndView.addObject("successMessage", "User has been registered successfully");
modelAndView.setViewName("register");
}
return modelAndView;
}
User entity
#Entity
#Table(name = "user")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "username",
unique = true)
private String username;
#Column(name = "email_address",
unique = true)
private String emailAddress;
#Column(name = "phone_number")
private String phoneNumber;
#Column(name = "password")
private String password;
#Column(name = "notification_type",
insertable = false)
private String notificationType = "email";
#Column(name = "date_created")
private Date dateCreated;
#Column(name = "is_active",
insertable = false)
private Boolean active = false;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<UserGroup> groups;
#OneToMany(
mappedBy = "user",
cascade = CascadeType.ALL,
orphanRemoval = true
)
private List<Message> messages = new ArrayList<>();
#OneToOne(fetch = FetchType.LAZY,
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
mappedBy = "userId",
orphanRemoval = true)
private VerificationToken verificationToken;
#OneToMany(mappedBy = "createdBy",
cascade = {CascadeType.DETACH, CascadeType.MERGE,
CascadeType.REFRESH, CascadeType.PERSIST},
orphanRemoval = true)
private List<Group> createdGroups = new ArrayList<>();
//getters and setters
Related
I'm creating a new java entity with html post form,but I don't understand how to convert system id to a class System (that I pass with model.addAttribute("System",id); in controller).
Release
#Table(name = "treleas")
public class Release {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "release_id")
Integer releaseId;
#Column(name = "release_name", nullable = false)
private String releaseName;
#Column(name = "create_date", nullable = false)
private LocalDateTime releaseDate = LocalDateTime.now();
#ManyToOne
#JoinColumn(name = "system_id")
private System system;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="release_id")
private List<Req> requirements;
}
System
#Entity
#Table(name = "tsystem")
public class System {
#Id
#Column(name = "system_id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
Integer systemId;
#Column(name = "system_name", nullable = false)
private String systemName;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name="system_id")
private List<Release> releases;
}
Html new release
<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Новый релиз</title>
</head>
<body>
<form th:method="POST" th:action="#{|/systems/${System}/releases|}"
th:object="${release}">
<label for="releaseName" >Введите название релиза: </label>
<input type="text" th:field="*{releaseName}" id="releaseName"/>
<div style="color:#f80d0d" th:if="${#fields.hasErrors('releaseName')}" th:errors="*{releaseName}"
>Name error</div>
<input type="hidden" th:field="*{system}" th:value="|${System}|"/>
<br/>
<input type="submit" value="Create!"/>
</form>
</body>
</html>
Exception
Caused by: org.postgresql.util.PSQLException: ОШИБКА: значение NULL в столбце "system_id" отношения "treleas" нарушает ограничение NOT NULL
Подробности: Ошибочная строка содержит (5, ReleaseName, 2022-05-15, null).
which means that it cannot insert release with a null system id
Hi I need a little help with my code. I tried solutions online but I couldn't fix my bug. I working in java and spring with mysql and tymeleaf. My error is short:
Invalid property 'projection' of bean class [com.bakulic.CinemaTicketShop.model.dto.requests.CreateOrUpdateProjectionDTO]: Bean property 'projection' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
And I found that my problem is in the html file createProjectionForm whitch I will put below as well as the entities and all that is needed. My projection entity has a relation to Hall and Movie and I'm not sure how to get attributes of Movie and Hall in my html. For the fiel I tried to put ${projection.hall.name} and ${projection.movie.movieName}. Zou will find it in the code.
Thank you in advance.
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "projections")
public class Projection {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int projectionId;
#Column(name = "date")
private String date;
#Column(name = "startTime")
private String startTime;
#ManyToOne
#JoinColumn(name = "idHall")
private Hall hall;
#ManyToOne
#JoinColumn(name = "idMovie")
private Movie movie;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Seat> seatList;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "projection", cascade = CascadeType.ALL)
private List<Ticket> ticketList;
}
#Entity
#Table(name = "halls")
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Hall {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int hallId;
#Column(name = "name")
private String name;
#Column(name = "numberofseats")
private Integer numberOfSeats;
#Column(name = "description")
private String description;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "hall", cascade = CascadeType.ALL)
private List<Projection> projectionList;
}
#Entity
#Table(name = "movies")
#Data
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
public class Movie {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private int movieId;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#Column (name = "length")
private String length;
#Column(name = "picture")
private String picture;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "movie", cascade = CascadeType.ALL)
private List<Projection> projectionList;
}
#Data
public class ProjectionDTO implements Serializable {
private int id;
private String date;
private String startTime;
private List<Seat> seatList;
private List<Ticket> ticketList;
private Hall hall;
private Movie movie;
public ProjectionDTO(Projection projection){
if(projection != null){
this.id = projection.getProjectionId();
this.date = projection.getDate();
this.startTime = projection.getStartTime();
this.seatList = projection.getSeatList();
this.ticketList = projection.getTicketList();
this.hall = projection.getHall();
this.movie = projection.getMovie();
}
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class CreateOrUpdateProjectionDTO implements Serializable {
private String date;
private String startTime;
private List<Seat> seatList;
//aditional info
private String name;
private String movieName;
}
/** create projection*/
public Projection createProjection(CreateOrUpdateProjectionDTO createProjectionDTO){
if(createProjectionDTO == null){
throw new InvalidDataException("Projection cannot be null");
}
timeValidator.checkTime(createProjectionDTO.getStartTime());
dateValidator.checkDate(createProjectionDTO.getDate());
Projection proj = new Projection();
proj.setDate(createProjectionDTO.getDate());
proj.setStartTime(createProjectionDTO.getStartTime());
Hall hall = proj.getHall();
if(hall == null){
hall = new Hall();
}
hall.setName(createProjectionDTO.getName());
Integer numOfSeats = hall.getNumberOfSeats();
Movie movie = proj.getMovie();
if(movie == null){
movie = new Movie();
}
movie.setName(createProjectionDTO.getMovieName());
List<Seat> list = createProjectionDTO.getSeatList();
for(int i=1; i<=numOfSeats; i++ ){
Seat seat = new Seat();
seat.setSeatNumber(i);
seat.setStatus("empty");
list.add(seat);
}
Projection projCreated = projectionRepository.save(proj);
log.info(String.format("Projection %s has been created.", proj.getProjectionId()));
return projCreated;
} The function is similar for update.
<
<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Create theater</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
</head>
<body style="background-color:lightgrey;">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<img src="../pictures/cinemalogo.png" th:src="#{pictures/cinemalogo.png}" class = "center"alt="logo" width="120" height="100"/>
<ul class="navbar-nav">
<li class="nav-item">
<h1>Our cinema!</h1>
</li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/logout">Logout</a>
</li>
</ul>
</nav>
</nav>
<br>
<br>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1>Add projection</h1><br>
<form th:action="#{/projection}" method="post" th:object="${projection}">
<div class="form-group">
<label class="control-label" for="date"> Date </label>
<input id="date" class="form-control" th:field="*{date}"
required autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="startTime"> Start time</label> <input
id="startTime" class="form-control" th:field="*{startTime}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="hallName"> Hall name </label> <input
id="hallName" class="form-control" th:field="*{projection.hall.name}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<label class="control-label" for="movieName"> Movie name </label> <input
id="movieName" class="form-control" th:field="*{projection.movie.movieName}" required
autofocus="autofocus" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
Use th:field="*{hall.name}" instead of th:field="*{projection.hall.name}" and th:field="*{movie.movieName}" instead of th:field="*{projection.movie.movieName}"
I'm working on a JPA project in which I have two models: TableDecor and Product Tag, which look like this:
#Entity(name="table_decor")
public class TableDecor {
#Id
#IdConstraint
private String id;
#Positive
#Column(nullable = false)
private int width;
#Positive
#Column(nullable = false)
private int height;
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private Color color;
#NotNull
#Enumerated(EnumType.STRING)
#Column(nullable = false)
private Fabric fabric;
#ManyToMany
#JoinTable(
name = "seller",
joinColumns = #JoinColumn(name = "table_decor_id"),
inverseJoinColumns = #JoinColumn(name = "seller_id"))
private List<Seller> sellers;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="producer_id")
private Producer producer;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "product_tag_id", referencedColumnName = "id")
private ProductTag productTag;
// getters, setters
#Entity(name="product_tag")
#Table
public class ProductTag {
#Id
#GeneratedValue
private UUID id;
#NotNull
#Enumerated
#Column(nullable = false)
private ProductState productState;
#Column(nullable = false)
#NotNull
private float price;
#OneToOne(cascade=CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "table_decor_id", referencedColumnName = "id")
private TableDecor tableDecor;
// getters, setters
As you can see they're connected with each other with bidirectional one to one relationship. Since one can't exist without another, how can I create a Thymeleaf add form that could create both objects at the same time? The controller function currently looks like this:
#GetMapping("/table-decor/add")
public String showAddForm(TableDecor decorToAdd, ProductTag productTag) {
return "table-decor-add";
}
#PostMapping("/table-decor/add-new")
public String addTableDecor(#Valid TableDecor decorToAdd, #Valid ProductTag productTag, BindingResult bindingResult, Model model){
if (bindingResult.hasErrors()) {
System.out.println("Error");
return "table-decor-add";
}
decorToAdd.setProductTag(productTag);
tableDecorService.addTableDecor(decorToAdd);
model.addAttribute("allTableDecor", tableDecorService.getAllTableDecor());
return "redirect:/table-decor";
and the form:
<form action="#" method="post" th:action="#{/table-decor/add-new}">
<div><input name="id" type="text" th:value="${tableDecor.id}"></div>
<span th:if="${#fields.hasErrors('tableDecor.id')}" th:errors="*{tableDecor.id}"></span>
<div><input name="width" type="text" th:value="${tableDecor.width}"></div>
<span th:if="${#fields.hasErrors('tableDecor.width')}" th:errors="*{tableDecor.width}"></span>
<div><input name="height" type="text" th:value="${tableDecor.height}"></div>
<span th:if="${#fields.hasErrors('tableDecor.height')}" th:errors="*{tableDecor.height}"></span>
<select name="color">
<option th:each="color : ${T(jee.labs.lab05.domain.Color).values()}"
th:text="${color}"
th:value="${tableDecor.color}">
</option>
</select>
<select name="fabric">
<option th:each="fabric : ${T(jee.labs.lab05.domain.Fabric).values()}"
th:text="${fabric}"
th:value="${tableDecor.fabric}">
</option>
</select>
<select name="productState">
<option th:each="productState : ${T(jee.labs.lab05.domain.ProductState).values()}"
th:text="${productState}"
th:value="${productTag.productState}">
</option>
</select>
<div><input name="price" type="text" th:value="${productTag.price}"></div>
<span th:if="${#fields.hasErrors('productTag.price')}" th:errors="*{productTag.price}"></span>
<div><input type="submit" th:value="Submit"></div>
</form>
I have a form for editing a user, the user has roles, which are a list of objects of type Authority, I want to be able to use checkboxes (optional) to set the roles that the user will have, but I have no idea how to implement the form in thymeleaf and how to pass the user object with the given roles to the controller.
It's my user
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.Set;
#Entity
#Table(name = "users")
#Data
#NoArgsConstructor
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name="username", nullable = false, unique = true)
#NotBlank #Size(min=5, message = "Не менeе 5 знаков")
private String username;
#NotBlank #Size(min=5, message = "Не менeе 5 знаков")
#Column(name = "password")
private String password;
#Column(name = "enabled")
private boolean enabled;
#Column(name = "name")
private String name;
#Column(name = "surname")
private String surname;
#Column(name = "email", nullable = false, unique = true)
private String email;
#ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.DETACH,
CascadeType.REFRESH
}, fetch = FetchType.EAGER)
#JoinTable(
name = "users_authorities",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "authority_id")
)
private Set<Authority> authorities = new HashSet<>();
public User(String username, String password, boolean enabled,
String name, String surname, String email) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.name = name;
this.surname = surname;
this.email = email;
}
public void addAuthority(Authority authority) {
this.authorities.add(authority);
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
}
It's my edit user form contoller
#GetMapping("/users/{id}/edit")
public String editUser(#PathVariable("id") Long id, Model model) {
model.addAttribute("user", userService.findById(id));
model.addAttribute("allAuthorities", authorityService.findAll());
return "users/edit-user";
}
It's my edit user form view
<body>
<form th:method="PUT" th:action="#{/admin/users/{id}(id=${user.getId()})}" th:object="${user}">
<input type="hidden" th:field="*{id}" id="id">
<label for="username">Username: </label>
<input type="text" th:field="*{username}" id="username" placeholder="username">
<br><br>
<div sec:authorize="hasRole('ROLE_ADMIN')">
<label for="enabled">Enabled </label>
<input type="checkbox" name="enabled" th:field="*{enabled}" id="enabled">
<br><br>
</div>
<label for="name">Name: </label>
<input type="text" th:field="*{name}" id="name" placeholder="Name">
<br><br>
<label for="surname">Surname: </label>
<input type="text" th:field="*{surname}" id="surname" placeholder="Surname">
<br><br>
<label for="email">Email: </label>
<input type="text" th:field="*{email}" id="email" placeholder="Email">
<br><br>
<div th:each="auth:${allAuthorities}">
<label>
<span th:text="${auth.authority}"></span>
<input type="checkbox" name="authorities" th:checked="${user.authorities.contains(auth)}">
</label>
</div>
<input type="submit" value="Edit">
</form>
</body>
It's put contoller, it getting the data from my form
#PutMapping("/users/{id}")
public String editUser(#PathVariable("id") Long id,
#ModelAttribute("user") User user,
#RequestParam("authorities") List<Authority> authorities) {
user.setId(id);
userService.update(user);
return "redirect:/admin/users";
}
And it's my Authority class if you need
#Entity
#Table(name = "authorities")
#Data
#NoArgsConstructor
public class Authority implements GrantedAuthority {
#Id
private Long id;
#Column(name = "authority")
private String authority;
#Transient
#ManyToMany(mappedBy = "authorities")
private Set<User> users;
public Authority(Long id, String authority) {
this.id = id;
this.authority = authority;
}
}
I'm try to pass the list of roles separately from the user object, but this also doesn't work and gives a bad request error.
To solve the problem, I added a new checked field to Entity authority
#Entity
#Table(name = "authorities")
#Data
#NoArgsConstructor
public class Authority implements GrantedAuthority {
#Id
private Long id;
#Column(name = "authority", nullable = false, unique = true)
private String authority;
#Transient
private boolean checked;
public Authority(Long id, String authority) {
this.id = id;
this.authority = authority;
}
}
Before sending the view to it, I changed the authorites field of the user object.
#GetMapping("/users/{id}/edit")
public String editUser(#PathVariable("id") Long id, Model model) {
User user = userService.findById(id);
List<Authority> allAuthorities = authorityService.findAll();
for(Authority auth : allAuthorities) {
if(user.getAuthorities().contains(auth)) {
auth.setChecked(true);
}
}
user.setAuthorities(allAuthorities);
model.addAttribute("user", user);
return "users/edit-user";
}
I also changed the thymeleaf template
<form th:method="PUT" th:action="#{/admin/users/{id}(id=${user.getId()})}" th:object="${user}">
<label for="username">Username: </label>
<input type="text" th:field="*{username}" id="username" placeholder="username">
<br><br>
<div sec:authorize="hasRole('ROLE_ADMIN')">
<label for="enabled">Enabled </label>
<input type="checkbox" name="enabled" th:field="*{enabled}" id="enabled">
<br><br>
</div>
<label for="name">Name: </label>
<input type="text" th:field="*{name}" id="name" placeholder="Name">
<br><br>
<label for="surname">Surname: </label>
<input type="text" th:field="*{surname}" id="surname" placeholder="Surname">
<br><br>
<label for="email">Email: </label>
<input type="text" th:field="*{email}" id="email" placeholder="Email">
<br><br>
<div th:each="auth, itemStat: ${user.authorities}">
<label>
<span th:text="${auth.authority}"></span>
<input type="hidden"
th:field="*{authorities[__${itemStat.index}__].id}">
<input type="hidden"
th:field="*{authorities[__${itemStat.index}__].authority}">
<input type="checkbox" th:checked="${auth.checked}"
th:field="*{authorities[__${itemStat.index}__].checked}">
</label>
</div>
<input type="submit" value="Edit">
</form>
My put controller looks like this
#PutMapping("/users/{id}")
public String editUser(#PathVariable("id") Long id,
#ModelAttribute("user") User user) {
List<Authority> userAuthorities = user.getAuthorities();
userAuthorities.removeIf(auth -> !auth.isChecked());
user.setId(id);
userService.update(user);
return "redirect:/admin/users";
}
My save and delete methods from UserService look like this(If that would be useful)
#Override
#Transactional
public User save(User user) {
Optional<User> userFromDB = userRepository.findByUsername(user.getUsername());
Optional<Authority> userRole;
if(userFromDB.isPresent()) {
return null;
}
userRole = authorityRepository.findByAuthority("ROLE_USER");
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
userRole.ifPresent(user::addAuthority);
return userRepository.save(user);
}
#Override
#Transactional
public User update(User user) {
Optional<User> userFromDB = userRepository.findById(user.getId());
if(userFromDB.isPresent()){
//Adding the password for successfully update user in DB
user.setPassword(userFromDB.get().getPassword());
return userRepository.save(user);
}
return null;
}
This may not be the most elegant solution but I haven't found another one yet
I am making a registration page for a website, but when I go to the page I get the error: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor'
Controller
#RequestMapping(value = { "/signup" }, method = RequestMethod.POST)
public ModelAndView createUser(#Valid AppUser appUser, BindingResult bindingResult) {
ModelAndView model = new ModelAndView();
AppUser appUserExists = appUserService.findByEmail(appUser.getEmail());
if (appUserExists != null) {
bindingResult.rejectValue("email", "error.user", "This email already exists!");
}
if (bindingResult.hasErrors()) {
model.setViewName("user/signup");
} else {
appUserService.saveUser(appUser);
model.addObject("msg", "User has been registered succesfully!");
model.addObject("appuser", new AppUser());
model.setViewName("user/login");
}
return model;
}
Form
<form class="form-horizontal" role="form" th:action="#{/signup}" th:object="${appUser}" method="post" style="border: 1px solid #ccc">
<label for="name">First Name</label>
<input type="text" th:field="*{firstname}" class="form-control" id="firstname" placeholder="First Name" required autofocus />
<label for="name">Last Name</label>
<input type="text" th:field="*{lastname}" class="form-control" id="lastname" placeholder="Last name" required autofocus />
<label for="email"><b>Email</b></label>
<input type="email" th:field="*{email}" class="form-control" id="email" placeholder="email#domain.com" required autofocus />
<label for="psw"><b>Password</b></label>
<input type="password" th:field="*{password}" class="form-control" id="password" placeholder="Password" required />
</form>
AppUser Class
#Entity
#Table(name = "user")
public class AppUser {
#Id
#Column(name = "id_user", length = 10, nullable = false, unique = true)
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "firstname", length = 30, nullable = false, unique = true)
private String firstName;
#Column(name = "lastname", length = 30, nullable = false, unique = true)
private String lastName;
#Column(name = "email", length = 30, nullable = false, unique = true)
private String email;
#Column(name = "password", length = 500, nullable = false, unique = false)
private String password;
#Column(name = "active", nullable = false)
private int active;
public AppUser() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
....
}
From what I can see, there's nothing wrong here so I'm stuck.
Any ideas?
The appuser variable in the controller should be appUser. And the lastname and the firstname in the template must be lastName and firstName like in the class.