【问题标题】:Cannot update record with children using Thymeleaf and Spring Boot - Getting NullPointerException无法使用 Thymeleaf 和 Spring Boot 更新儿童记录 - 获取 NullPointerException
【发布时间】:2016-07-30 15:11:04
【问题描述】:

我在 SO 中寻找过类似的问题,虽然我发现了一些相关问题,但没有一个得到回答。所以我在这里发布我的问题,希望能有更好的运气。

我有一个父记录 Resource 和孩子(一对多)ResourceSkills。我可以在用于编辑资源的 Thymeleaf 页面上显示 ResourceResourceSkills 的值,但是在保存时,我在控制器类中看到 ResourceSkills 为 Null。这会导致 NullPointerException。

代码如下:

资源

@Entity
public class Resource {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;

    @Version
    private Integer version;

    private String firstName;
    private String lastName;

    @OneToMany (mappedBy = "resource", orphanRemoval=false, fetch=FetchType.EAGER)
    private List<ResourcesSkills> skills;

    @ManyToOne (fetch=FetchType.EAGER)
    @JoinColumn(name="project_id")
    private Project project; 


    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public List<ResourcesSkills> getSkills() {
        return skills;
    }

    public void setSkills(List<ResourcesSkills> skills) {
        this.skills = skills;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public Project getProject() {
        return project;
    }

    public void setProject(Project project) {
        this.project = project;
    }
}

资源技能

@Entity
@IdClass(ResourcesSkillsId.class)
public class ResourcesSkills {

    @Id
    @ManyToOne
    @JoinColumn(name="resource_id")
    private Resource resource;

    @Id
    @ManyToOne
    @JoinColumn(name = "skill_id")
    private Skill skill; 

    @Version
    private Integer version;

    private boolean primarySkill;

    public Resource getResource() {
        return resource;
    }

    public void setResource(Resource resource) {
        this.resource = resource;
    }

    public Skill getSkill() {
        return skill;
    }

    public void setSkill(Skill skill) {
        this.skill = skill;
    }

    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    public boolean isPrimarySkill() {
        return primarySkill;
    }

    public void setPrimarySkill(boolean primarySkill) {
        this.primarySkill = primarySkill;
    }
}

资源控制器

@Controller
public class ResourceController {

    ResourceService resourceService;
    SkillService skillService;

    @Autowired
    public void setResourceService(ResourceService resourceService){
        this.resourceService = resourceService;
    }

    @Autowired
    public void setSkillService(SkillService skillService){
        this.skillService = skillService;
    }

    @RequestMapping(value="resources", method = RequestMethod.GET)
    public String list(Model model){
        model.addAttribute("resources", resourceService.listAllResources());
        return "resources";
    }

    @RequestMapping(value="resource/{id}")
    public String showResource(@PathVariable Integer id, Model model){
        model.addAttribute("resource", resourceService.getResourceById(id));
        return "resourceshow";
    }

    @RequestMapping(value = "resource/new")
    public String newResource(Model model){
        model.addAttribute("resource", new Resource());
        model.addAttribute("skills", skillService.listAllSkills());
        return "resourceform";
    }

    @RequestMapping(value = "resource/edit/{id}")
    public String editResource(@PathVariable Integer id, Model model){
        Resource resource = resourceService.getResourceById(id);
        model.addAttribute("resource", resource);
        return "resourceform";
    }

    @RequestMapping(value = "resource/delete/{id}")
    public String deleteResource(@PathVariable Integer id){
        resourceService.deleteResource(id);
        return "redirect:/resources";
    }

    @RequestMapping(value = "resource", method = RequestMethod.POST)
    public String saveResource(Resource resource){

        /* AT THIS POINT resource.skills is NULL and save FAILS */
        ResourceService.saveResource(resource);
        return "redirect:/resource/" + resource.getId(); 
    }
}

最后是 Thymeleaf 代码:

<h2>Resource Details</h2>
    <div>
        <form class="form-horizontal" th:object="${resource}" th:action="@{/resource}" method="post">
            <input type="hidden" th:field="*{id}"/>
            <input type="hidden" th:field="*{version}"/>
            <div class="form-group">
                <label class="col-sm-2 control-label">First name:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" th:field="*{firstName}"/>
                </div>
                <label class="col-sm-2 control-label">Surname:</label>
                <div class="col-sm-10">
                    <input type="text" class="form-control" th:field="*{lastName}"/>
                </div>
            </div>
            <div>
                <table class="table table-stripped">
                    <tr>
                        <th>Skill</th>
                        <th>Primary</th>
                    </tr>
                    <tr th:each="resSkill : *{skills}">
                        <td th:text="${resSkill.skill.description}">Skill Description</td>
                        <td><input type="checkbox" name="primary" th:disabled="disabled" th:checked="${resSkill.primarySkill}" /></td>
                    </tr>
                </table>
                <a th:href="${'/resourceSkills/' + resource.id}">Edit Skills</a>
            </div>
            <div class="row">
                <button type="submit" class="btn btn-default">Submit</button>
            </div>
        </form>
    </div>

我得到的错误如下(供参考):

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause

java.lang.NullPointerException: null
        at eu.kororos.ccplanner.controllers.ResourceController.saveResource(ResourceController.java:79) ~[classes/:na]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_65]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_65]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_65]
        at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_65]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]

【问题讨论】:

    标签: java spring spring-boot spring-data-jpa thymeleaf


    【解决方案1】:

    您好像忘了@Autowire ResourceService 和 SkillsService?

    【讨论】:

    • 感谢 Marco 的回复,但我不确定我明白了……这就是我在 ResourceController 的前两种方法中所做的。我需要在上面做点什么吗?
    猜你喜欢
    • 1970-01-01
    • 2015-01-30
    • 2017-09-02
    • 1970-01-01
    • 1970-01-01
    • 2017-09-28
    • 2012-01-13
    • 1970-01-01
    • 2015-07-29
    相关资源
    最近更新 更多