【问题标题】:What is the correct way to use Spring MVC and JPA to update a model?使用 Spring MVC 和 JPA 更新模型的正确方法是什么?
【发布时间】:2014-05-14 15:18:05
【问题描述】:

我正在使用 SpringMVC 和 SpringJPA。即使我不开发 Web 服务,我也更喜欢使用 REST 风格。

在前端我使用 Thymeleaf,在后端我有一个实体/模型项目,例如:

    @Entity
    @Table(name = "projects")
    public class Project extends AbstractPersistable<Long> {

        private static final long serialVersionUID = 7075433538058077502L;

        @Size(min = 2, max = 30)
        @NotBlank
        private String name;

        @NotNull
        @Enumerated(EnumType.STRING)
        private ProjectCategory category;

        @Temporal(TemporalType.DATE)
        @NotNull
        @DateTimeFormat(iso = ISO.DATE)
        private Date startDate;

        @Temporal(TemporalType.DATE)
        @NotNull
        @DateTimeFormat(iso = ISO.DATE)
        private Date endDate;

在 AbstractPersistable 中,setId 方法是受保护的,所以我不能将 id 目录设置为这个实体。 (我知道我可以覆盖 setId 方法,但我认为这不是对 id 进行操作的正确方法,SpringJPA 将 setId 方法定义为 protected 肯定有一些原因。)

我的控制器是这样的:

    @RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
    public String edit(@PathVariable("id") Long id, Model model) {
        model.addAttribute("project", projectService.find(id));
        return "projects/edit";
    }

    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public ModelAndView update(@PathVariable("id") Long id, @Valid Project project, BindingResult result, RedirectAttributes redirect) {           

        if (result.hasErrors()) {
            return new ModelAndView("projects/edit");
        }

        try {
            projectService.update(project);
            logger.info(project.getName() + " project has been updated.");
            redirect.addFlashAttribute(GLOBAL_MESSAGE, "Project updated successfully.");
        } catch (BusinessException e) {
            ModelAndView view = new ModelAndView("projects/edit");
            view.addObject(BUSINESS_ERROR, e.getMessage());
            return view;
        }

        return new ModelAndView(redirectTo("/projects"));
    }

现在,在我的控制器中,SpringMVC 无法设置 Project 对象的 id。一个问题是,如果 BindingResult 中有一些错误,我需要使用没有 id 值的 Project 对象将请求转发到“projects/edit”视图,以让用户输入正确的项目信息。

我的视图形式是这样的:

<form id="project-form" th:action="@{'/projects/' + ${project.id}}" th:object="${project}" th:method="put" class="form-horizontal">
</form>

那么form标签中的action属性就不会有项目的id值了。用户在更正错误后无法重新提交表单,因为操作是 /projects/null

如何正确使用 SpringMVC、SpringJPA 和 REST 风格?对我来说,对 SpringMVC API 有什么误解吗?

有没有为 SpringMVC 和 SpringJPA 提供完整 CRUD 的示例和开源项目?

【问题讨论】:

  • 这个抽象类的目的是什么?对于我能想到的大多数情况来说,这似乎有点矫枉过正。
  • 这个摘要来自 Spring JPA。我认为我们不应该直接修改 ID,因为实体应该由 EntityManager 管理。

标签: spring rest spring-mvc


【解决方案1】:

我也遇到过这个问题。好像有两种方法:

  1. 覆盖 setId(如您所述)
  2. 在您的控制器类的 POST/PUT 方法中调用 setId(您的路径中有 ID)。

我已经覆盖了我的 setId ;)

编辑:

好吧,在与其他形式的斗争之后,我有了一个很好的解决方案。我用过活页夹。在控制器类中我已经对其进行了初始化:

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(Player.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                Player custom = repositoryPlayerService.findById(Integer.parseInt(text));
                setValue(custom);
            }
        });
     }

在我的 JSP 中的 FORM 标记中:

      <form:form id="updatePlayerForm" action='' modelAttribute="player" method="post">
      ....
     <input id="player" type="hidden" name="player" value="${player.id}" />
     ....
     </form:form>

通过这种方式,您将获得一个实体(您正在使用的 od 数据对象),其 ID 在控制器的 POST 方法中填写。

【讨论】:

  • 我正在使用 SessionAttribute 和 ModelAttribute 将 ID 绑定到我的模型。表单提交后,会调用 SessionStatus.setComplete()。这是我的解决方案。
  • 嗯...在这种情况下,关于 ID 的信息加倍。当您的 ID 在您的 @PathVariable("id") 中时,您不需要另一个带有 ID 的会话属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 2018-02-16
  • 1970-01-01
  • 2020-03-31
  • 2021-04-06
相关资源
最近更新 更多