百里香叶绑定集合
[英] thymeleaf binding collections
本文介绍了百里香叶绑定集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我在使用 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="#{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() 更好.我将感谢建设性的批评.
再次感谢 Andrew 和 Blejzer 没有你的帮助我不会这样做.我已将您的回答标记为有用.
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屋!
查看全文