我有一个Project对象的编辑表单。在所有可用角色的完整列表中,每个项目都有一个与其关联的角色列表。我需要一个复选框列表来选择角色。我在这个代码示例中实现了它,感谢StackOverflow,使用Formatter:https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple
问题:我创建的表单允许我选择角色并成功保存。但是,当我显示现有的项目对象进行编辑时,列表中不会检查已与该项目关联的角色。所有复选框都清晰。
上面的代码示例带有String id。我使用Long id。我认为这就是问题的原因,但我不知道如何解决它。我应该完全放弃Formatter方法吗?有没有办法使这项工作?
到目前为止,这是我的代码:
项目类:
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/www.example.com.csr.pem -out certs/www.example.com.cert.pem
Using configuration from openssl.cnf
Enter pass phrase for /Users/myssl/private/ca.key.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 4096 (0x1000)
Validity
Not Before: Oct 31 18:43:27 2017 GMT
Not After : Nov 10 18:43:27 2018 GMT
Subject:
countryName = IN
stateOrProvinceName = KAR
organizationName = ABC
commonName = www.example.com
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Server
Netscape Comment:
OpenSSL Generated Server Certificate
X509v3 Subject Key Identifier:
D7:12:DB:DE:D1:92:52:15:E5:AD:83:84:B6:7F:9F:CF:97:06:91:8E
X509v3 Authority Key Identifier:
keyid:1C:5F:64:BB:8B:E5:8E:A7:DE:00:E2:D7:1A:D5:1D:52:53:5E:59:32
DirName:/C=IN/ST=KAR/L=BLR/O=ABC/CN=www.example.com
serial:C3:D6:EE:B0:FE:28:76:14
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
Certificate is to be certified until Nov 10 18:43:27 2018 GMT (375 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
角色类:
@Entity
public class Project
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
private List<Role> rolesNeeded;
public Project()
{
rolesNeeded = new ArrayList<>();
}
//getters and setters omitted for brevity
}
控制器:
@Entity
public class Role
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Column
private String name;
public Role() {}
//getters and setters omitted for brevity
}
RoleFormatter:
@Controller
public class ProjectController
{
@Autowired
private ProjectService projectService;
@Autowired
private RoleService roleService;
@RequestMapping(value = "/projects/save", method = RequestMethod.POST)
public String addProject(@Valid Project project)
{
projectService.save(project);
return "redirect:/";
}
@RequestMapping("/projects/{id}/edit")
public String editForm(@PathVariable Long id, Model model)
{
Project project = projectService.findById(id);
model.addAttribute("project", project);
model.addAttribute("allRoles", roleService.findAll());
return "project/form";
}
}
最后是Thymeleaf形式:
@Component
public class RoleFormatter implements Formatter<Role>
{
@Override
public Role parse(String id, Locale locale) throws ParseException
{
Role role = new Role();
role.setId(Long.parseLong(id));
return role;
}
@Override
public String print(Role role, Locale locale)
{
String id = role.getId() + "";
return id;
}
}
更新
正如评论中所讨论的:当我不使用上面的Formatter时,我收到400 Bad Request错误。这是POST请求的标头数据。在这种情况下,我尝试选择两个角色(ID 1和3,如下所示)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<body>
<section>
<div class="container wrapper">
<form th:action="@{/projects/save}" method="post" th:object="${project}">
<input type="hidden" th:field="*{id}"/>
<div>
<label for="project_name"> Project Name:</label>
<input type="text" id="project_name" th:field="*{name}"/>
</div>
<div>
<label>Project Roles:</label>
<ul class="checkbox-list">
<li th:each="role : ${allRoles}">
<input type="checkbox" th:id="${{role}}" th:value="${{role}}" th:field="*{rolesNeeded}" />
<span class="primary" th:text="${role.name}"></span>
</li>
</ul>
</div>
<div class="actions">
<button type="submit" value="Save" class="button">Save</button>
<a th:href="@{/}" class="button button-secondary">Cancel</a>
</div>
</form>
</div>
</section>
</body>
</html>
答案 0 :(得分:2)
在您的情况下完全删除格式化程序,并执行类似
的复选框 <input type="checkbox" th:value="${role.id}" th:field="*{rolesNeeded}" th:text="${role.name}"/>
这应该有效。来自复选框的Id将自动解释为现有实体ID,并将从数据库中获取。
格式化程序旨在生成某些对象的本地化表示,而不是Web表单和辅助bean之间的转换器。是的我知道有些教程正在教pplmto这样做,但请不要。也许过去的某一天,在旧版本的spring或thymeleaf中,它是正确的解决方案,但现在它更像是一个黑客,而不是一个怎么做的thigs-right模式。
PS:这是工作申请的一部分
控制器方法声明:
public String addPlacePost(@Valid final Place place, BindingResult placeValidation, Model model) {
复选框标记:
<fieldset th:object="${place}" th:classappend="${#fields.hasErrors('services')} ? 'has-error' : _ ">
<legend>Select services</legend>
<div class="checkbox" th:each="service : ${allServices}">
<label> <input th:value="${service.id}" th:field="*{services}" type="checkbox"/> <span
th:text="${service.name}" th:remove="tag"> </span>
</label>
</div>
<span class="help-block" th:each="msg : ${#fields.errors('services')}" th:text="${msg}">Some error message for this field</span>
</fieldset>
包含Place
Services
实体部分
@ManyToMany
@JoinTable(joinColumns = @JoinColumn(name = "place_id"), inverseJoinColumns = @JoinColumn(name = "service_id"))
@NotEmpty
private Set<Service> services;
在添加新地点以及编辑现有地点方面都像魅力一样。
答案 1 :(得分:0)
向前跑 - 这里有一个完整的Github示例和解释 - &gt; https://stackoverflow.com/a/46926492/6332774
现在针对您的案例发表评论:
如果您没有得到解决,请查看Thymeleaf团队的回复:
在你的情况下,你的getRolesNeeded()方法需要返回一个数组,其中数组的大小需要等于复选框的数量。
为此,您可以使用此处记录的AttributeConverter https://stackoverflow.com/a/34061723/6332774
添加StringListConverter类(如上面的链接)并将模型类更改为:
@Convert(converter = StringListConverter.class)
private List<String> rolesNeeded = new ArrayList<>();
...
public List<String> getRolesNeeded() {
return rolesNeeded;
}
public void setRolesNeeded(List<String> rolesNeeded) {
this.rolesNeeded = rolesNeeded;
}
然后在您的html复选框输入中删除ID,如@Antoniossss所示。把它改成这样的东西:
<div th:each="roles : ${allRoles_CanAddRolesArrayInController}">
<input type="checkbox" th:field="*{rolesNeeded}" th:value="${role.id}"/><label th:text="${role.name}">Role1</label>
</div>
希望它有所帮助。