Thymeleaf复选框列出传递值,但不显示现有值

时间:2017-10-31 19:31:02

标签: spring-boot thymeleaf

我有一个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>

2 个答案:

答案 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团队的回复:

http://forum.thymeleaf.org/The-checked-attribute-of-the-checkbox-is-not-set-in-th-each-td3043675.html

在你的情况下,你的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>

希望它有所帮助。