在Spring中自定义表单bean创建过程

时间:2015-10-31 10:13:18

标签: java spring spring-mvc spring-form spring-mvc-initbinders

我有以下bean:

public class TerminalAdmin {

    @Id
    @Column(name = "admin_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
    @SequenceGenerator(name = "user_id", sequenceName = "user_id")
    private Long adminId;

    @Column(name = "email", nullable = false)
    private String email;

    @Column(name = "phone")
    @Size(max = 255)
    private String phone;

    @Size(max = 255)
    @Column(name = "name")
    private String name;

    @Column(name = "registration_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar createDate;

    @Column(name = "password", nullable = false)
    @Size(min=1, max = 255, message = "введите пароль длиной от 1 до 255 символов")
    private String password;

    @ManyToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
    @JoinTable(name = "admin_role", joinColumns = { 
            @JoinColumn(name = "admin_id", nullable = false) }, 
            inverseJoinColumns = { @JoinColumn(name = "role_id", 
                    nullable = false) })
    private Set<AdminRole> adminRoles;

    @Column(name = "blocked")
    private boolean blocked;
    ...
}

和此:

public class AdminRole {    

    @Id
    @Column(name = "role_id", nullable = false, unique = true)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
    @SequenceGenerator(name = "user_id", sequenceName = "user_id")
    private Long id;

    @Column(name = "role")
    private String role;
    ....
}

内部控制器:

@RequestMapping(value = "/admin/addNewAdmin")
public String adminUsers(@Valid TerminalAdmin terminalAdmin,
            BindingResult bindingResult, ModelMap model, Principal principal, HttpSession session) {

从客户端我发送以下请求:

enter image description here

terminalAdmin来到这个方法

enter image description here

  1. 为什么spring将值写入role字段?
  2. 如何强制将250 / 251写入id字段?
  3. P.S。

    我试着写

    InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(AdminRole.class, new PropertyEditorSupport() {
            public void setAsText(String name) {
                ....
            }
        });
    }
    

    setAsText方法无法调用。

1 个答案:

答案 0 :(得分:0)

将模型对象填充到表单中这不是一个好习惯,因为如果未正确配置init绑定器,Spring可以将字段绑定到对象,即使它们未填充到视图中也是如此。

最简单的方法是创建DTO对象,例如。你可以创建AdminTerminalDTO或AdminTerminalForm,你可以填充到视图中。

表单可以包含与AdminTerminal相同的字段,不包括ID字段或任何其他敏感字段。您无法从视图中插入新ID,因为它可能导致数据库完整性错误。

成功验证后,您只需保留模型对象,并使用DTO / Form Object填充它。

此外,您的JSR-303注释似乎没有以正确的方式使用。

@Size Annotation不适合检查字符串长度。你必须使用@Length。您使用@Size来检查数组的长度。 @Size也适用于字符串,但@Length更准确。

  1. 你不能只发送一个Integer并尝试绑定到你的Set(spring会做一些奇怪的绑定,你现在可以看到)。相反,您已经在控制器中完成了addNewAdmin方法,该方法已经通知它添加了管理员用户。
  2. 您必须在此方法中在服务器端分配管理员角色。首先你可以使用包含例如的DTO。用户名,密码和其他字段。你用适当的JSR-303注释来表示它们。使用bindingResult检查是否存在任何验证错误。如果表单经过验证,则只需将DTO / Form对象转换为Model对象即可。然后,您可以添加管理员角色并保留模型对象。
  3. 如果这些提示不够,我可以编写一些示例代码。

    编辑:

    public class TerminalAdminDTO {
    
        private String username;
    
        @Length(max = 255)
        public String getUsername(){
            return username;
        }
    
        public void setUsername(String username){
            this.username = username;
        }
    
        public TerminalAdmin convertToTerminalAdmin(){
            TerminalAdmin terminalAdmin = new TerminalAdmin();
            terminalAdmin.setUsername(this.username);
            return terminAdmin;
        }
    
    }
    
    
    @Entity
    @Table
    public class TerminalAdmin {
    
        @Id
        @Column(name = "admin_id", nullable = false, unique = true)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_id")
        @SequenceGenerator(name = "user_id", sequenceName = "user_id")
        private Long adminId;
    
        @Column(name = "email", nullable = false)
        private String email;
    
        @Column(name = "phone")
        @Size(max = 255)
        private String phone;
    
        @Size(max = 255)
        @Column(name = "name")
        private String name;
    
        @Column(name = "registration_date")
        @Temporal(TemporalType.TIMESTAMP)
        private Calendar createDate;
    
        @Column(name = "password", nullable = false)
        @Size(min=1, max = 255, message = "введите пароль длиной от 1 до 255 символов")
        private String password;
    
        @ManyToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
        @JoinTable(name = "admin_role", joinColumns = { 
                @JoinColumn(name = "admin_id", nullable = false) }, 
                inverseJoinColumns = { @JoinColumn(name = "role_id", 
                        nullable = false) })
        private Set<AdminRole> adminRoles;
    
        @Column(name = "blocked")
        private boolean blocked;
        ...
    }
    
    
    @RequestMapping(value = "/admin/addNewAdmin")
    public String adminUsers(@Valid TerminalAdminDTO terminalAdminDTO,
                BindingResult bindingResult, ModelMap model, Principal principal, HttpSession session) {
                        if(result.hasErrors()){
                            return "errorPage";
                        }else{
                            userService.createAdminUser(terminalAdminDTO);
                            return "successPage";
                        }
                }
    
    
    @Service
    @Transactional
    public class UserServiceImpl implements UserService {
    
        private final int ADMIN_ROLE_ID = 0;
    
        @Autowired
        EntityManager entityManager;
    
        public void createAdminUser(TerminalAdminDTO terminalAdminDTO){
            TerminalAdmin terminalAdmin = terminalAdminDTO.convertToTerminalAdmin();
            AdminRole adminRole = entityManager.find(AdminRole.class,ADMIN_ROLE_ID);
            terminalAdmin.getAdminRoles().add(adminRole);
            entityManager.create(terminalAdmin);
        }
    
    }
    

    我把它写成了做这件事的一个例子,这不是一个现成的代码