百里香叶绑定集合 [英] thymeleaf binding collections

查看:31
本文介绍了百里香叶绑定集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在使用 spring 和 thymeleaf 绑定集合时遇到问题.每次我发送表单时,我的对象集合都设置为空(User.postions),我的示例如下:

我的控制器:

@RequestMapping(value = urlFragment + "/add", method = RequestMethod.GET)公共字符串 addPosition(模型模型){HashSet<位置>position = new HashSet(positionRepository.findByEnabledTrueOrderByNameAsc());用户员工 = 新用户();对于(位置位置:位置){员工.addPosition(职位);}model.addAttribute("员工", 员工);return "crud/employee/add";}@RequestMapping(value = urlFragment + "/add", method = RequestMethod.POST)public String processNewEmployee(Model model, @Valid @ModelAttribute("employee") 用户员工,BindingResult 结果) {String templatePath = "crud/employee/add";如果(!result.hasErrors()){userRepository.save(员工);model.addAttribute("成功", true);}返回模板路径;}

还有我的员工表格:

<div class="row"><div class="col-md-6"><label th:text="#{first_name}">名字</label><input class="form-control" type="text" th:field="*{userProfile.firstName}"/>

<div class="row"><div class="col-md-6"><label th:text="#{last_name}">姓氏</label><input class="form-control" type="text" th:field="*{userProfile.lastName}"/>

<div class="row"><div class="col-md-6"><label th:text="#{email}">电子邮件</label><input class="form-control" type="text" th:field="*{email}"/>

<div class="row"><div class="col-md-6"><label th:text="#{position}">Position</label><select th:field="*{positions}" class="form-control"><option th:each="位置:*{位置}"th:value="${position.id}"th:text="${position.name}"> 线框</选项></选择>

<div class="row"><div class="col-md-5"><div class="checkbox"><button type="submit" class="btn btn-success" th:text="#{add_employee}">添加员工

</表单>

用户实体:

@Entity@Table(name="`用户`")公共类用户扩展 BaseModel {@Column(unique = true, nullable = false, length = 45)私人字符串电子邮件;@Column(可为空 = 假,长度 = 60)私人字符串密码;@柱子私人字符串名称;@柱子启用私有布尔值;@ManyToMany(fetch = FetchType.EAGER, 级联 = CascadeType.ALL)@JoinTable(name = "user_role",joinColumns = {@JoinColumn(name = "user_id", nullable = false)},inverseJoinColumns = {@JoinColumn(name = "role_id", nullable = false)})私人收藏<角色>角色 = new HashSet();@ManyToMany(fetch = FetchType.LAZY, 级联 = CascadeType.ALL)@JoinTable(name = "user_position",joinColumns = {@JoinColumn(name = "user_id", nullable = false)},inverseJoinColumns = {@JoinColumn(name = "position_id", nullable = false)})私人收藏<位置>position = new HashSet();公共用户(){}公共用户(字符串电子邮件,字符串密码,启用布尔值){this.email = 电子邮件;this.password = 密码;this.enabled = 启用;}公共用户(字符串电子邮件,字符串密码,启用布尔值,设置<角色>角色){this.email = 电子邮件;this.password = 密码;this.enabled = 启用;this.roles = 角色;}公共字符串 getEmail() {回邮件;}公共无效setEmail(字符串电子邮件){this.email = 电子邮件;}公共布尔 isEnabled() {返回已启用;}公共无效设置启用(布尔启用){this.enabled = 启用;}公共字符串 getName() {返回名称;}公共无效集名称(字符串名称){this.name = 名称;}公共字符串 getPassword() {返回密码;}public void setPassword(字符串密码){this.password = 密码;}公共收藏<位置>获取位置(){返回位置;}private void setPositions(Collectionpositions) {this.positions = 职位;}公共布尔 addPosition(位置位置){返回位置.添加(位置);}公共布尔 removePosition(位置位置){返回positions.remove(position);}公共集合<角色>获取角色(){回归角色;}private void setRoles(Collection roles) {this.roles = 角色;}公共布尔 addRole(角色角色){返回角色.添加(角色);}公共布尔 removeRole(角色角色){返回roles.remove(role);}@覆盖公共字符串 toString() {返回 User.class + " - id: " + getId().toString() + ", email: " + getEmail();}}

我在某处读到我必须创建 equals() 和 hashCode(),所以我在我的位置实体中做了.

public boolean equals(Position position) {返回 this.getId() == position.getId();}公共 int hashCode(){返回 this.getId().hashCode() ;}

这里是post方法发送的数据:

这是我的结果:

我的spring版本:4.1.6.RELEASEthymeleaf-spring4 版本:2.1.4.RELEASEthymeleaf-layout-dialect 版本:1.2.8

当然,我希望位置是 HashCode,其中一个元素为 id = 2 的对象 Position.你可以帮帮我吗?我做错了什么?

解决方案

感谢大家回答我的问题.你帮了我很多.不幸的是,我不得不在一件事上不同意你的观点.您向我展示了以下示例:

newPosition.setId(position.getId());

相同的示例位于 Andrew github 存储库中.我认为使用 setId() 方法是不好的做法.因此,我将介绍我的解决方案,并等待一些评论,然后再将其标记为答案.

WebMvcConfig 类

@Configuration@EnableWebMvc@ComponentScan(basePackages = "com.smartintranet")公共类 WebMvcConfig 扩展了 WebMvcConfigurerAdapter {@PersistenceContext私有 EntityManager 实体管理器;//(....其余的方法.......)@覆盖public void addFormatters(FormatterRegistry formatterRegistry) {formatterRegistry.addFormatter(new PositionFormatter(entityManager));}}

PositionFormatter 类

public class PositionFormatter 实现了Formatter;{私有 EntityManager 实体管理器;公共 PositionFormatter(EntityManager entityManager) {this.entityManager = entityManager;}公共字符串打印(位置位置,语言环境){if(position.getId() == null){返回 "";}返回 position.getId().toString();}public Position parse(String id, Locale locale) 抛出 ParseException {return entityManager.getReference(Position.class, Long.parseLong(id));}}

employeeForm.html

 

<label th:text="#{position}">Position</label><select th:field="*{position}" class="form-control"><option th:each="位置:${allPositions}"th:value="${position.id}"th:text="${position.name}"> 线框</选项></选择>

最后一个,EmployeeController 类

@Controller公共类 EmployeeController 扩展 AbstractCrudController {//(...其余的依赖和方法....)@交易@RequestMapping(value = urlFragment + "/create", method = RequestMethod.GET)公共字符串createNewEmployee(模型模型){准备员工表格(模型);return "crud/employee/create";}@交易@RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)public String processNewEmployee(Model model, @ModelAttribute("employee") Employee employee, BindingResult 结果) {如果(!result.hasErrors()){//看这里是很重要的一行!entityManager.merge(employee.getUser());}准备员工表格(模型);return "crud/employee/create";}}

这是我的解决方案.这里有什么不好?我认为那行:

entityManager.merge(employee.getUser());

我不能在这里使用:

userRepository.save(employee.getUser());

因为 Position 实体是分离的,当我使用 save 方法时,它在这种情况下运行 em.persist() 所以我手动运行 em.merge().我知道这段代码并不完美,但我认为这个解决方案比使用 setId() 更好.我将感谢建设性的批评.

再次感谢 AndrewBlejzer 没有你的帮助我不会这样做.我已将您的回答标记为有用.

I have a problem with binding collections using spring and thymeleaf. Every time I send form, my object collections are set to null (User.postions), my example below:

My Controller:

@RequestMapping(value = urlFragment + "/add", method = RequestMethod.GET)
public String addPosition(Model model) {

    HashSet<Position> positions = new HashSet<Position>(positionRepository.findByEnabledTrueOrderByNameAsc());

    User employee = new User();

    for (Position position : positions) {
        employee.addPosition(position);
    }

    model.addAttribute("employee", employee);

    return "crud/employee/add";
}

@RequestMapping(value = urlFragment + "/add", method = RequestMethod.POST)
public String processNewEmployee(Model model, @Valid @ModelAttribute("employee") User employee, BindingResult result) {
    String templatePath = "crud/employee/add";

    if (!result.hasErrors()) {
        userRepository.save(employee);
        model.addAttribute("success", true);
    }

    return templatePath;
}

And my employee form:

<form action="#" th:action="@{/panel/employee/add}" th:object="${employee}" method="post">

    <div class="row">
        <div class="col-md-6">
            <label th:text="#{first_name}">First name</label>
            <input class="form-control" type="text" th:field="*{userProfile.firstName}"/>
        </div>
    </div>

    <div class="row">
        <div class="col-md-6">
            <label th:text="#{last_name}">Last name</label>
            <input class="form-control" type="text" th:field="*{userProfile.lastName}"/>
        </div>
    </div>

    <div class="row">
        <div class="col-md-6">
            <label th:text="#{email}">Email</label>
            <input class="form-control" type="text" th:field="*{email}"/>
        </div>
    </div>

    <div class="row">
        <div class="col-md-6">
            <label th:text="#{position}">Position</label>
            <select th:field="*{positions}" class="form-control">
                <option th:each="position : *{positions}"
                        th:value="${position.id}"
                        th:text="${position.name}">Wireframe
                </option>
            </select>
        </div>
    </div>


    <div class="row">
        <div class="col-md-5">
            <div class="checkbox">
                <button type="submit" class="btn btn-success" th:text="#{add_employee}">
                    Add employee
                </button>
            </div>
        </div>
    </div>
</form>

User entity:

@Entity
@Table(name="`user`")
public class User extends BaseModel {

    @Column(unique = true, nullable = false, length = 45)
    private String email;

    @Column(nullable = false, length = 60)
    private String password;

    @Column
    private String name;

    @Column
    private boolean enabled;

    @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(name = "user_role",
            joinColumns = {@JoinColumn(name = "user_id", nullable = false)},
            inverseJoinColumns = {@JoinColumn(name = "role_id", nullable = false)}
    )
    private Collection<Role> roles = new HashSet<Role>();

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "user_position",
            joinColumns = {@JoinColumn(name = "user_id", nullable = false)},
            inverseJoinColumns = {@JoinColumn(name = "position_id", nullable = false)}
    )
    private Collection<Position> positions = new HashSet<Position>();

    public User() {
    }

    public User(String email, String password, boolean enabled) {
        this.email = email;
        this.password = password;
        this.enabled = enabled;
    }

    public User(String email, String password, boolean enabled, Set<Role> roles) {
        this.email = email;
        this.password = password;
        this.enabled = enabled;
        this.roles = roles;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Collection<Position> getPositions() {
        return positions;
    }

    private void setPositions(Collection<Position> positions) {
        this.positions = positions;
    }

    public boolean addPosition(Position position) {
        return positions.add(position);
    }

    public boolean removePosition(Position position) {
        return positions.remove(position);
    }

    public Collection<Role> getRoles() {
        return roles;
    }

    private void setRoles(Collection<Role> roles) {
        this.roles = roles;
    }

    public boolean addRole(Role role) {
        return roles.add(role);
    }

    public boolean removeRole(Role role) {
        return roles.remove(role);
    }

    @Override
    public String toString() {
        return User.class + " - id: " + getId().toString() + ", email: " + getEmail();
    }
}

I have read somewhere that I have to create equals() and hashCode(), so I did it in my Position Entity.

public boolean equals(Position position) {
    return this.getId() == position.getId();
}

public int hashCode(){
    return this.getId().hashCode() ;
}

Here are data sent by post method:

And here is my result:

My spring version: 4.1.6.RELEASE thymeleaf-spring4 version: 2.1.4.RELEASE thymeleaf-layout-dialect version: 1.2.8

O course I wish positions to were HashCode with one element of object Position with id = 2. Could you help me? What I am doing wrong?

解决方案

Thanks Guys for answering my question. You help me a lot. Unfortunately I have to disagree with you in one thing. You have shown me example with:

newPosition.setId(position.getId());

The same example was in Andrew github repository. I think that this is bad practice to use setId() method. So I will present my solution and I will wait for some comments before I will mark it as an answer.

WebMvcConfig Class

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.smartintranet")
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @PersistenceContext
    private EntityManager entityManager;

    // (....rest of the methods.......)

    @Override
    public void addFormatters(FormatterRegistry formatterRegistry) {
        formatterRegistry.addFormatter(new PositionFormatter(entityManager));
    }
}

PositionFormatter class

public class PositionFormatter implements Formatter<Position> {

    private EntityManager entityManager;

    public PositionFormatter(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public String print(Position position, Locale locale) {
        if(position.getId() == null){
            return "";
        }

        return position.getId().toString();
    }

    public Position parse(String id, Locale locale) throws ParseException {
        return entityManager.getReference(Position.class, Long.parseLong(id));
    }
}

employeeForm.html

                <div class="col-md-6">
                    <label th:text="#{position}">Position</label>
                    <select th:field="*{position}" class="form-control">
                        <option th:each="position : ${allPositions}"
                                th:value="${position.id}"
                                th:text="${position.name}">Wireframe
                        </option>
                    </select>
                </div>

And last one, EmployeeController Class

@Controller
public class EmployeeController extends AbstractCrudController {    
    // (...rest of dependency and methods....)

    @Transactional
    @RequestMapping(value = urlFragment + "/create", method = RequestMethod.GET)
    public String createNewEmployee(Model model) {
        prepareEmployeeForm(model);
        return "crud/employee/create";
    }

    @Transactional
    @RequestMapping(value = urlFragment + "/create", method = RequestMethod.POST)
    public String processNewEmployee(Model model, @ModelAttribute("employee") Employee employee, BindingResult result) {
        if (!result.hasErrors()) {
            // Look here it is important line!
            entityManager.merge(employee.getUser());
        }

        prepareEmployeeForm(model);

        return "crud/employee/create";
    }
}

It is my solution. What is bad here? I think that line:

entityManager.merge(employee.getUser());

I can't use here:

userRepository.save(employee.getUser());

Because Position entity is detached, and when I use save method it runs in this situation em.persist() so I ran manually em.merge(). I know that this code is not perfect but I think that this solution is better then use setId(). I will be grateful for constructive critic.

One more time thanks Andrew and Blejzer for help without you I would not do it. I have marked yours answer as useful.

这篇关于百里香叶绑定集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
Java开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆