首页 > 解决方案 > Thymeleaf:将角色应用于用户时出现字段错误(一对多关系)

问题描述

我正在尝试制作一个 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);
    
}

RoleRepository.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> {
    
}

用户服务.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;
    }
}

用户注册控制器.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”;嵌套异常是 org.springframework.core.convert.ConversionFailedException: 无法从类型 [java.lang.String] 转换为值 'com.example.demo.model.Role@6e32df30' 的类型 [java.lang.Long];嵌套异常是 java.lang.NumberFormatException:对于输入字符串:“com.example.demo.model.

所以,我想我的代码应该做的是使用我们从表单 (${role}) 中获得的 Role 值,并将其应用于 User.java 中的 Role 变量,在关系中连接它们。相反,似乎发生的是,它不是从表单中获取角色值,而是从表单中获取“com.example.demo.model.Role@[random id]”的字符串值。

我对 Spring Boot 和 Thymeleaf 还是很陌生。有谁知道是什么问题?我已经尝试了几个小时来查找这个确切问题的解决方案,但我仍然找不到任何对我有帮助的东西。提前致谢。

标签: javamysqlspringspring-bootthymeleaf

解决方案


好的,我环顾四周,终于自己找到了解决方案。原来我必须通过 th:value="${role.id}" 而不是 "${role}"。这是我所做的更改:

用户注册控制器.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>

希望这可以帮助任何同样困惑的人。


推荐阅读