Я пытаюсь создать приложение Thymeleaf, которое может зарегистрировать учетную запись с прикрепленной ролью, выбранной во время регистрации. Вот визуализация. Я постараюсь добавить как можно больше релевантного кода, чтобы лучше понять, что происходит, а затем объяснить проблему.
Пользователь.java:
package com.example.demo.model;
<imports>
@Entity
@Table(name = "user", uniqueConstraints = @UniqueConstraint(columnNames = "account"))
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
private String account;
private String password;
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "role_id", nullable=false)
private Role role;
@OneToMany(mappedBy = "user")
private Collection<Comment> comments;
public User() {
}
public User(String firstName, String lastName, String account, String password, Role role,
Collection<Comment> comments) {
super();
this.firstName = firstName;
this.lastName = lastName;
this.account = account;
this.password = password;
this.role = role;
this.comments = comments;
}
<getters and setters>
}
Роль.java:
package com.example.demo.model;
<imports>
@Entity
@Table(name = "role")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(fetch=FetchType.LAZY, mappedBy = "role")
private Set<User> users = new HashSet<User>(0);
public Role() {
}
public Role(String name, Set<User> users) {
super();
this.name = name;
this.users = users;
}
<getters and setters>
}
Комментарий.java:
<not important>
Пользовательский репозиторий.java:
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.model.User;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
User findByAccount(String account);
}
Ролевепозиторий.java:
package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.demo.model.Role;
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
}
UserService.java:
package com.example.demo.service;
<imports>
@Service("userService")
public class UserService {
private UserRepository userRepository;
@Autowired
private BCryptPasswordEncoder passwordEncoder;
public UserService(UserRepository userRepository) {
super();
this.userRepository = userRepository;
}
public User findByAccount(String account) {
return userRepository.findByAccount(account);
}
public void saveUser(User user) {
userRepository.save(user);
}
}
РольСервис.java:
package com.example.demo.service;
<imports>
@Service
public class RoleService {
private RoleRepository roleRepository;
public RoleService(RoleRepository roleRepository) {
super();
this.roleRepository = roleRepository;
}
}
UserRegistrationController.java:
package com.example.demo.web;
<imports>
@Controller
@RequestMapping("/registration")
public class UserRegistrationController {
private UserService userService;
@ModelAttribute("user")
public User user() {
return new User();
}
@Autowired
RoleRepository roleRepository;
@GetMapping
public String showRegistrationForm(Model model) {
model.addAttribute("roles", roleRepository.findAll());
return "registration";
}
@PostMapping
public String registerUserAccount(User user) {
System.out.println();
userService.saveUser(user);
return "redirect:/registration?success";
}
}
SecurityConfiguration.java (на всякий случай):
package com.example.demo.config;
<imports>
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers(
"/registration**",
"/js/**",
"/css/**",
"/img/**").permitAll().anyRequest().authenticated().
and().formLogin().loginPage("/login").permitAll().
and().logout().invalidateHttpSession(true).clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login?logout")
.permitAll();
}
}
Соответствующий фрагмент кода из Registration.html:
<form th:action = "@{/registration}" method = "post" th:object = "${user}">
<div class = "form-group">
<label class = "control-label" for = "firstName">First name</label> <input
id = "firstName" class = "form-control" th:field = "*{firstName}"
required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "lastName">Last name</label> <input
id = "lastName" class = "form-control" th:field = "*{lastName}"
required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "account">Account</label> <input
id = "account" class = "form-control" th:field = "*{account}" required
autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "password">Password</label> <input
id = "password" class = "form-control" type = "password"
th:field = "*{password}" required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "role">Role</label>
<select class = "form-control" th:field = "*{role}" id = "role">
<option th:each = "role: ${roles}" th:value = "${role}" th:text = "${role.name}"></option>
</select>
</div>
<div class = "form-group">
<button type = "submit" class = "btn btn-success">Register</button>
<span>Already registered? <a href = "/" th:href = "@{/login}">Login
here</a></span>
</div>
</form>
Проблема: Всякий раз, когда я пытаюсь создать пользователя с выбранной ролью, я получаю следующую ошибку:
Ошибка поля в объекте «пользователь» в поле «роль»: отклоненное значение [com.example.demo.model.Role@6e32df30]; коды [typeMismatch.user.role, typeMismatch.role, typeMismatch.com.example.demo.model.Role, typeMismatch]; аргументы [org.springframework.context.support.DefaultMessageSourceResolvable: коды [user.role,role]; аргументы []; сообщение по умолчанию [роль]]; сообщение по умолчанию [Не удалось преобразовать значение свойства типа 'java.lang.String' в требуемый тип 'com.example.demo.model.Role' для свойства 'role'; вложенным исключением является org.springframework.core.convert.ConversionFailedException: не удалось преобразовать тип [java.lang.String] в тип [java.lang.Long] для значения 'com.example.demo.model.Role@6e32df30'; вложенным исключением является java.lang.NumberFormatException: для входной строки: "com.example.demo.model.Role@6e32df30"]]
Итак, я предполагаю, что мой код должен использовать значение роли, которое мы получаем из формы (${role}), и применять его к переменной роли в User.java, соединяя их в отношениях. Вместо этого, по-видимому, происходит то, что вместо того, чтобы принимать значение роли, оно принимает строковое значение «com.example.demo.model.Role@[random id]» из формы.
Я все еще новичок в Spring Boot и Thymeleaf. Кто-нибудь знает, в чем проблема? Я пытался найти решения именно этой проблемы в течение многих часов, но до сих пор не могу найти ничего, что помогло бы мне. Заранее спасибо.




Хорошо, я еще немного осмотрелся и, наконец, сам нашел решение. Оказывается, мне пришлось передать th:value="${role.id}" вместо "${role}". Вот изменения, которые я сделал:
UserRegistrationController.java:
package com.example.demo.web;
<imports>
@Controller
@RequestMapping("/registration")
public class UserRegistrationController {
private UserService userService;
public UserRegistrationController(UserService userService) {
super();
this.userService = userService;
}
@Autowired
RoleRepository roleRepository;
@GetMapping
public String showRegistrationForm(Model model, User user) {
model.addAttribute("roles", roleRepository.findAll());
return "registration";
}
@PostMapping
public String registerUserAccount(@Valid @ModelAttribute("user") User user, BindingResult result) {
userService.saveUser(user);
return "redirect:/registration?success";
}
}
Соответствующий фрагмент кода из Registration.html:
<form th:action = "@{/registration}" method = "post" th:object = "${user}">
<div class = "form-group">
<label class = "control-label" for = "firstName">First name</label> <input
id = "firstName" class = "form-control" th:field = "*{firstName}"
required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "lastName">Last name</label> <input
id = "lastName" class = "form-control" th:field = "*{lastName}"
required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "account">Account</label> <input
id = "account" class = "form-control" th:field = "*{account}" required
autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "password">Password</label> <input
id = "password" class = "form-control" type = "password"
th:field = "*{password}" required autofocus = "autofocus" />
</div>
<div class = "form-group">
<label class = "control-label" for = "role">Role</label>
<select class = "form-control" th:field = "*{role}" id = "role">
<option th:each = "role: ${roles}" th:value = "${role.id}" th:text = "${role.name}"></option>
</select>
</div>
<div class = "form-group">
<button type = "submit" class = "btn btn-success">Register</button>
<span>Already registered? <a href = "/" th:href = "@{/login}">Login
here</a></span>
</div>
</form>
Надеюсь, это поможет любому, кто был так же сбит с толку.