使用Spring MVC和JPA更新模型的正确方法是什么?

时间:2014-05-14 15:18:05

标签: spring rest spring-mvc

我正在使用SpringMVC和SpringJPA。而且我更喜欢使用REST风格,即使我没有开发Web服务。

在我使用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方法定义为受保护。)

我的控制器就像:

    @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>

然后,表单标记中的action属性将不具有项目的id值。由于操作是/ projects / null

,因此用户无法在更正错误后重新提交表单

如何正确使用SpringMVC,SpringJPA和REST风格?对我来说,有没有关于SpringMVC API的误解?

是否有任何示例和开源项目具有SpringMVC和SpringJPA的完整CRUD?

1 个答案:

答案 0 :(得分:0)

我也一直面临着这个问题。似乎有两种方法:

  1. 覆盖setId(如您所述)
  2. 在控制器类的POST / PUT方法中调用setId(路径中有ID)。
  3. 我已经覆盖了我的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);
                }
            });
         }
    

    在FORM标签的JSP中:

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

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